百度之星Valley Numer

24 篇文章 0 订阅

Problem Description
众所周知,度度熊非常喜欢数字。

它最近发明了一种新的数字:Valley Number,像山谷一样的数字。
当一个数字,从左到右依次看过去数字没有出现先递增接着递减的“山峰”现象,就被称作 Valley Number。它可以递增,也可以递减,还可以先递减再递增。在递增或递减的过程中可以出现相等的情况。

比如,1,10,12,212,32122都是 Valley Number。

121,12331,21212则不是。

度度熊想知道不大于N的Valley Number数有多少。

注意,前导0是不合法的。

Input
第一行为T,表示输入数据组数。

每组数据包含一个数N。

● 1≤T≤200

● 1≤length(N)≤100

Output
对每组数据输出不大于N的Valley Number个数,结果对 1 000 000 007 取模。

Sample Input
3
3
14
120
Sample Output
3
14
119

很裸的一个数位DP,第一个切的就是这题。。
但是我还是只会写深搜版本啊,正统DP版不会。。但是深搜好写的

#include<cstdio>
#include<cstring>
typedef long long LL;
const int MOD=1000000007;
char ss[105];
LL yy[105][3][3][3][15];
int n;
LL dfs (int now,bool a,bool b,bool c,int last)
//当前到第几位   是否出现了小   是否已经是递增   是否已经有第一个非0位  上一个是什么
{
    if (now>n) return 1;
    if (yy[now][a][b][c][last]!=-1) return yy[now][a][b][c][last];
    int lalal=ss[now]-'0';//这一位是什么
    LL ans=0;
    if (c==false)//前面都是0
    {
        if (now==1)//还是第一位,不可以乱填 
        {
            ans=ans+dfs(now+1,true,false,false,0);
            ans%=MOD;
            for (int u=1;u<lalal;u++)
            {
                ans=ans+dfs(now+1,true,false,true,u);
                ans%=MOD;
            }
            ans=ans+dfs(now+1,false,false,true,lalal);
            ans%=MOD;
        }
        else//也就是我爱填什么填什么 
        {
            ans=ans+dfs(now+1,true,false,false,0);
            ans%=MOD;
            for (int u=1;u<=9;u++)
            {
                ans=ans+dfs(now+1,true,false,true,u);
                ans%=MOD;
            }
        }
    }
    else
    {
        if (a==false)//不可以越界 
        {
            if (b==false)//还不是递增
            {
                ans=ans+dfs(now+1,false,last<lalal,c,lalal);//我们这一位先填一样的
                ans%=MOD;
                if (lalal>last)
                {
                    for (int u=0;u<=last;u++)
                    {
                        ans=ans+dfs(now+1,true,false,c,u);
                        ans%=MOD;
                    }
                    for (int u=last+1;u<lalal;u++)
                    {
                        ans=ans+dfs(now+1,true,true,c,u);
                        ans%=MOD;
                    }
                }
                else    
                    for (int u=0;u<lalal;u++)
                    {
                        ans=ans+dfs(now+1,true,false,c,u);
                        ans%=MOD;
                    }
            }
            else//已经是递增了,不可以减了 
            {
                for (int u=last;u<lalal;u++)//我要填什么
                {
                    ans=ans+dfs(now+1,true,true,c,u);
                    ans%=MOD;
                }
                if (lalal>=last)
                {
                    ans=ans+dfs(now+1,false,true,c,lalal);
                    ans%=MOD;
                }
            }
        }
        else//已经可以越界了 
        {
            if (b==false)//目前还不是递增状态
            {
                for (int u=0;u<=9;u++)//填什么 
                {
                    ans=ans+dfs(now+1,true,last<u,c,u);
                    ans%=MOD;
                }
            }
            else//已经是递增 
            {
                for (int u=last;u<=9;u++)
                {
                    ans=ans+dfs(now+1,true,true,c,u);
                    ans%=MOD;
                }
            }
        }
    }
    yy[now][a][b][c][last]=ans;
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        memset(yy,-1,sizeof(yy));
        scanf("%s",ss+1);
        n=strlen(ss+1);
        printf("%d\n",(dfs(1,false,false,false,0)%MOD-1+MOD)%MOD);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值