HDU 6148 数位dp

题意:给你一个区间[1,r],然后在这个区间中的数字,从左往右看如果是先递增再递减的,这个就是山峰数,求这个区间中不是山峰数的数量。。

分析:开始题目看错了,原来一个数字中只用出现一段是先增后减的,就算山峰。。比如12100-12199都是山峰数

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;
int s[105];
#define ll long long
#define inf 1000000007
char n[105];
ll dp[105][5][20];//题目理解的有问题,如果有的话,就全算
ll swdp(int pos,int lead,int ud,int now,int limit,int num)//当前位置,有无前导0,,现在是上升还是下降还是符合条件的,有无限制,现在是第几个数字(无前导零)
{
    if(pos<=0) return ud==3;
    if(!limit&&dp[pos][ud][now]!=-1) return dp[pos][ud][now];
    int ed = limit?s[pos]:9;
    ll ret=0;
    for(int i=0;i<=ed;i++)
    {
        int t1=ud;
        if(!lead&&num>=1&&t1<3){
            if(i<now)//递减
            {
                if(t1==0)
                    t1=1;
                else if(t1==2)
                        t1=3;
            }
            else if(i>now)//递增
                t1=2;
        }
        ret=(ret+swdp(pos-1,lead&&i==0,t1,i,limit&&i==ed,num+(lead&&i==0?0:1)))%inf;
    }
    if(!limit) dp[pos][ud][now]=ret%inf;
    return ret%inf;
}
ll zz=0;
ll solve(ll b)
{
    memset(s,0,sizeof(s));
    int u=0;
    while(b>0)
    {
        s[++u]=n[--b]-'0';
    }
    for(int i=u;i>=1;i--)
    {
        zz=(zz*10%inf+s[i])%inf;
    }
    ll ans=swdp(u,1,0,0,1,0)%inf;
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    while(T--)
    {
        scanf("%s",n);
        int len=strlen(n);
        zz=0;
        ll k=solve(len);
        ll zzz=(zz-k+inf)%inf;//不用k,直接用solve(len)来表示,用G++提交会wa?!
        printf("%I64d\n",zzz);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值