【HDU-6148】 Valley Numer(数位dp)

百度之星2017复赛1005 HDU-6148 Valley Numer

题意

不出现上升后直接下降数位的数,不超过n的有几个。前导零不算。

题解

dfs(当前数位的位置len,这位的数num,是否在上升up,是否有限制limit)
limit不用存到状态里,因为limit为true时不可能访问两次。
num=-1代表还没开始这个数的第一位,前面是前导零。
up=1时,不允许下降。

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define N 105
const ll M = 1e9+7;
using namespace std;

int t;
char s[N];
int mlen;
ll st[N][11][2];
void add(ll &x,ll v){
    x+=v;if(x>=M)x-=M;
}
ll dfs(int len,int num,int up,bool limit);
void work(int len,int num,int up,bool limit,int i,ll &ans){
    if(num==-1 && i==0){
        add(ans,dfs(len+1,-1,0,limit));
    }else{
        if(num==-1){
            add(ans,dfs(len+1,i,0,limit));
        }else if(i<num){
            if(up==0)
            add(ans,dfs(len+1,i,0,limit));
        }else if(i==num){
            add(ans,dfs(len+1,i,up,limit));
        }else{
            add(ans,dfs(len+1,i,1,limit));
        }
    }
}
ll dfs(int len,int num,int up,bool limit){
    if(len==mlen) return num != -1;
    if(!limit && (~num)&&(~st[len][num][up]))return st[len][num][up];
    ll ans=0;
    int b=limit?s[len]-'0':9;
    for(int i=0;i<=b;++i)
        work(len,num,up,i==b&&limit,i,ans);
    return num<0||limit?ans:st[len][num][up]=ans;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        mlen=strlen(s);
        mem(st,-1);
        printf("%lld\n",dfs(0,-1,0,1));
    }
    return 0;
}
posted @ 2017-08-18 19:33  水郁  阅读(461)  评论(0编辑  收藏  举报
……