HDU 6148 数位dp

来源:互联网 发布:淘宝靠谱的美妆卖家 编辑:程序博客网 时间:2024/05/29 13:37

题意:给你一个区间[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 1000000007char 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;}