hdu 6148 (数位dp)

本文介绍了一种用于计算特定类型的数字——ValleyNumber数量的算法。ValleyNumber是一种没有‘山峰’现象的数字,即从左到右数字不会出现先递增再递减的情况。文章提供了一个通过动态规划解决该问题的实现方案,并给出了解决方案的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

它最近发明了一种新的数字: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

我这里算的是只要出现波峰就算不符合,然后用总的相减就好
代码有解释

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[110][10][4];
const int mod = 1e9+7;
string s;

ll dfs(int pos,int zero,int pre,int flag,int shang,int f)
{
    if(pos<0)
    {
    if(!zero&&f==1) return 1;
    //没有前导0并且出现波峰那么返回1,其实出现波峰肯定没有前导0return 0;
    }
    if(!zero&&dp[pos][pre][shang]!=-1&&!flag) return dp[pos][pre][shang];
    int up=flag?s[pos]-'0':9;
    ll res=0;
    for(int i=0;i<=up;i++)
    {
        if(zero&&i==0)
        {
            res+=dfs(pos-1,1,0,flag&&i==up,shang,0);
            res%=mod;
        }
        else {
            if(shang==3)
            {
                res+=dfs(pos-1,0,i,flag&&i==up,3,1);//出现过一个波峰,那么全都可以算 
                continue;
            }
            if(i==pre)
                res+=dfs(pos-1,0,i,flag&&i==up,shang,f);//和上一个数相同不影响上还是下 
            else if(i>pre&&shang==0&&zero==1)
            res+=dfs(pos-1,0,i,flag&&i==up,1,0); //如果有前导0还要上那么就上升一次 
            else if(i>pre&&shang==0&&!zero)
            res+=dfs(pos-1,0,i,flag&&i==up,2,0);//如果没有前导0那么直接上升两次,这是为了避免10这种情况 
            else if(i>pre&&shang==1) res+=dfs(pos-1,0,i,flag&&i==up,2,0);//如果上升过一次,那么还要上升一次才能算下降,因为
            //我的第一个数的前一个数是0,所以要消除这个的影响 
            else if(i<pre&&shang==2) res+=dfs(pos-1,0,i,flag&&i==up,3,1);
            //如果上升完了下降那么f=1 即出现波峰 
            else {
                res+=dfs(pos-1,0,i,flag&&i==up,shang,f);
            }
            res%=mod;
        }
    }
    if(!zero&&!flag)
    {
        dp[pos][pre][shang]=(res%mod);
    }
    return res;
}

int main()
{
    int T;
    scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    while(T--)
    {
        cin>>s;
        int len=s.length();
        ll aa=0;
        for(int i=0;i<len;i++)
        {
            aa=aa*10+(s[i]-'0');
            aa%=mod;
        }
        if(len==1)
        {
            printf("%d\n",s[0]-'0');
            continue;
        }
        reverse(s.begin(),s.end());
        ll ww=dfs(len-1,1,0,1,0,0);
        printf("%lld\n",(aa-ww+mod)%mod);
    }
    return 0;
}

正着做就是傻逼题了。。我是傻逼。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll dp[110][12][2];
string s;
const int mod = 1e9+7;

ll dfs(int pos,int zero,int pre,int flag,int sh)
{
    if(pos<0) return zero==0;
    if(!flag&&dp[pos][pre][sh]!=-1&&!zero) return dp[pos][pre][sh];
    int up=flag?s[pos]-'0':9;
    ll res=0;
    for(int i=0;i<=up;i++) 
    {
        if(zero&&i==0) res+=dfs(pos-1,1,pre,flag&&i==up,sh);
        else
        { 
        if(i==pre) res+=dfs(pos-1,0,i,flag&&i==up,sh);
        if(i>pre) res+=dfs(pos-1,0,i,flag&&i==up,1);
        if(i<pre&&!sh) res+=dfs(pos-1,0,i,flag&&i==up,sh);
        }
        res%=mod;
    }
    if(!flag)
        dp[pos][pre][sh]=res;
    return res%mod;
}

int main()
{
    int t;
    scanf("%d",&t);
    memset(dp,-1,sizeof(dp));
    while(t--)
    {
    cin>>s;
    reverse(s.begin(),s.end());
    printf("%lld\n",dfs(s.length()-1,1,10,1,0) );
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值