【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;
}

转载于:https://www.cnblogs.com/flipped/p/7391489.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值