HDU 3565 Bi-peak Number(數位DP)

題目鏈接:HDU 3565

題目大意:定義“雙峯數”爲滿足可以分割成兩個 /\ /\ 的形式的數,求區間[L,R]內雙峯數位數和的最大值。

題解:第一次寫數位DP,開篇BLOG記錄一下 ○(>_<)○
用記憶化搜索實現,dfs(int wei,int cur,int sta,bool fdn,bool fup)表示當前填到第wei位,上一位數字是cur,雙峯數的狀態爲sta,這一位的取值是(true)否(false)可能頂到上(fdn)下(fup)界時已經填的數位和最大值。
這裏sta=0~6分別表示:0還沒有開始填,1走到了第一個峯的上坡但是下一步不能直接向下走,2走到了第一個峯的上坡並且下一步可以向上也可以向下走,3走到了第一個峯的下坡處,4走到了第二個峯的上坡但是下一步不能直接向下走,5並且下一步可以向上也可以向下走,6走到了第二個峯的下坡並且之後之能向下走。大概是下面的樣子:

      _2_           _5_
    /     \       /     \
  1/       \3   4/       \6
  /         \   /         \
0            (_)           \

轉移的時候枚舉下一位填什麼數(注意上下界),判斷雙峯數的狀態,沒有頂到上下界的部分可以記憶化。代碼在下面:

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned long long ll;
inline ll read()
{
    char c=getchar(); ll num=0,f=1;
    while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
    while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); }
    return num*f;
}
ll T,L,R;
int dp[21][11][7],r[21],l[21];
int dfs(int wei,int cur,int sta,bool fdn,bool fup)
{
    if (wei==0) return (sta==6)?0:-1;
    if (!fdn&&!fup&&(~dp[wei][cur][sta])) return dp[wei][cur][sta];
    int mn=(fdn?l[wei]:0),mx=(fup?r[wei]:9),ret=-1;
    for (int i=mn;i<=mx;i++)
    {
        int tmp;
        switch (sta)
        {
            case 0: tmp=i?1:0; break;
            case 1: tmp=(i>cur)?2:-1; break;
            case 2: tmp=(i>cur)?2:((i<cur)?3:-1); break;
            case 3: tmp=(i<cur)?3:4; break;
            case 4: tmp=(i>cur)?5:-1; break;
            case 5: tmp=(i>cur)?5:((i<cur)?6:-1); break;
            case 6: tmp=(i<cur)?6:-1; break;
        }
        if (~tmp)
        {
            int num=dfs(wei-1,i,tmp,fdn&&i==mn,fup&&i==mx) ;
            if (~num) ret=max(ret,num+i);
        }
    }
    if (!fdn&&!fup) dp[wei][cur][sta]=ret;
    return ret;
}
int main()
{
    T=read(); memset(dp,-1,sizeof(dp));
    for (int i=1;i<=T;i++)
    {
        L=read(); R=read(); l[0]=r[0]=0;
        while (R)
        {
            l[++l[0]]=L%10,L/=10;
            r[++r[0]]=R%10,R/=10;
        }
        int ans=dfs(r[0],0,0,1,1); if (ans==-1) ans=0;
        printf("Case %d: %d\n",i,ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章