数位DP——Luogu3413 SAC#1

来源:互联网 发布:淘宝网汽车坐垫套途观l 编辑:程序博客网 时间:2024/06/04 21:26

题面:Luogu3413
这好像是我写的第一篇数位DP的blog吧。。。
半原创吧,参考的是我的同学lc233的blog:传送门
首先看到这个数据范围和样例就可以知道这题的主体思路了吧。
我们可以定义状态f[i][j][k]表示位数为i的,最高位为j,次高位为k的萌数个数。
一开始推的话很简单:

首先回文串嘛>2就好啦
所以我们只要判断2情况
aa或者aba; ——lc233

所以我们只要考虑连续两位的问题就好了。
所以接下来考虑统计答案的问题了。我们发现这个状态会有很多重复,很麻烦。
那么我们把f[i][j][k]定义为不是萌数的个数,这就好办多了。
接下来就是常规数位DP的写法了。。。

#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <iostream>#include <ctime>#include <map>#include <queue>#include <cstdlib>#include <string>#include <climits>#include <set>#include <vector>#define int long longusing namespace std;const int MOD=1e9+7;int f[1010][10][10];//注意这里f定义:这些数中不是萌数的个数,别搞错string l,r;inline int dp(string x){    int l=x.size(),n=0,ans=0;    for(int i=0;i<l;i++)n=(n*10+x[i]-'0')%MOD;n=(n==MOD)?0:n+1;    for(int i=2;i<l;i++)        for(int j=1;j<10;j++)            for(int k=0;k<10;k++)(ans+=f[i][j][k])%=MOD;    if(l>1)(ans+=10)%=MOD;//0~9    int la=-1,lla=-1;bool flag=1;    for(int i=0;i<l-1;i++){        int now=x[i]-'0';        for(int j=0;j<now;j++)if(i!=0||j!=0)            for(int k=0;k<10;k++)if(la!=j&&lla!=j&&j!=k&&k!=la)(ans+=f[l-i][j][k])%=MOD;        if(now==la||now==lla){flag=0;break;}        lla=la;la=now;    }    if(flag)for(int j=0;j<=x[l-1]-'0';j++)if(j!=la&&j!=lla)ans=(ans==MOD)?0:ans+1;    return (n-ans+MOD)%MOD;}//整个统计答案过程不多解释了signed main(){    ios::sync_with_stdio(0);    for(int i=2;i<=1000;i++)        for(int j=0;j<10;j++)            for(int k=0;k<10;k++)if(j!=k){                for(int l=0;l<10;l++)if(j!=l&&k!=l)(f[i][j][k]+=f[i-1][k][l])%=MOD;//如果没有出现回文现象加上去                if(i-1==1)f[i][j][k]=(f[i][j][k]==MOD)?0:f[i][j][k]+1;//从1开始            }    cin>>l>>r;    int ans=(dp(r)-dp(l)+MOD)%MOD;int L=l.size();    for(int i=1;i<L;i++)if(l[i]==l[i-1]||i>1&&l[i]==l[i-2]){ans++;break;}//上面的差分是l+1~r的,这里把l加上去    cout<<ans<<endl;    return 0;}
原创粉丝点击