LUOGU P3413 SAC#1 - 萌數(數位dp)
阿新 • • 發佈:2018-10-19
int length 一位數 位數 iostream amp str mat ostream
傳送門
解題思路
首先這道題如果有兩個以上長度的回文串,那麽就一定有三個或兩個的回文串,所以只需要記錄一下上一位和上上位填的數字就行了。數位\(dp\),用記憶化搜索來實現。設\(f[i][j][k][0/1]\)表示填到了第\(i\)位,上上位數字為\(j\),上一位數字為\(k\),\(0/1\)表示有沒有出現過回文串的方案數。\(dfs\)裏在套路的傳一個這一位有沒有限制和前導0,細節還是比較多的。
代碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 1005; const int MOD = 1e9+7; typedef long long LL; string l,r; int cnt,num[MAXN]; LL f[MAXN][15][15][2]; LL dfs(int x,int pre,int pree,bool lim,bool zero,int exist){ if(x==0) return exist; int Max=lim?num[x]:9,p;LL sum=0; if(f[x][pre][pree][exist]!=-1 && !lim && !zero) return f[x][pre][pree][exist]; for(int i=0;i<=Max;i++){ p=(zero&&i==0)?-1:i; int A=pre,B=pree; sum+=dfs(x-1,pree,p,(lim&&(p==num[x])),(p==-1),exist|(p!=-1 && (pree==p || pre==p))); sum%=MOD; } if(!zero && !lim) f[x][pre][pree][exist]=sum; return sum; } LL solve(string s,bool sub){ cnt=s.length(); for(int i=1;i<=cnt;i++) num[cnt-i+1]=s[i-1]-‘0‘; if(sub){ int now=1; while(num[now]==0) num[now++]=9; num[now]--; while(!num[cnt] && cnt) cnt--; } memset(f,-1,sizeof(f)); return dfs(cnt,-1,-1,1,1,0); } int main(){ cin>>l>>r; printf("%lld",((solve(r,0)-solve(l,1))%MOD+MOD)%MOD); return 0; }
LUOGU P3413 SAC#1 - 萌數(數位dp)