Sample Input
6 1212
Sample Output
298
给定一个数字字符串S,如果一个数字字符串(只包含0-9,可以有前导0)中出现且只出现1次S,我们就称这个字符串是好的。
例如假设S=666,则1666、03660666是好的,6666、66、123不是好的;假设S=1212,则01212、12123是好的,121212、121是不好的。
请你计算长度为N的数字字符串中,有多少个是好的。由于总数可能很大,你只需要输出总数模1000000007的余数。
Input一个整数N和一个数字串S。
对于30%的数据,1 ≤ N ≤ 8
对于100%的数据,1 ≤ N ≤ 1000,1 ≤ |S| ≤ N。
Output一个整数代表答案。
思路:dp[i][j][k],表示前i位,而且当前尾巴与S的前缀的最长公共长度位j,k表示是否出现过S。 对于第i位,枚举0到9,并且用KMP找到最长公共部分。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1010; const int Mod=1e9+7; int a[maxn],dp[maxn][maxn][2],ans,N,L; int Next[maxn]; char c[maxn]; void KMP() { for(int i=2,k=0;i<=L;i++){ while(k&&a[i]!=a[k+1]) k=Next[k]; if(a[i]==a[k+1]) k++; Next[i]=k; } } int get(int i,int j) { while(1){ if(a[i+1]==j) return i+1; if(i==0) break; i=Next[i]; }return 0; } int main() { scanf("%d%s",&N,c+1); L=strlen(c+1); a[L+1]=-1; rep(i,1,L) a[i]=c[i]-'0'; dp[0][0][0]=1; KMP(); rep(i,1,N){ rep(j,0,min(i-1,L)){ rep(k,0,9) { int t=get(j,k); if(j==L-1){ if(t==L) (dp[i][t][1]+=dp[i-1][j][0])%=Mod; else { (dp[i][t][1]+=dp[i-1][j][1])%=Mod; (dp[i][t][0]+=dp[i-1][j][0])%=Mod; } } else { if(t!=L) (dp[i][t][1]+=dp[i-1][j][1])%=Mod; (dp[i][t][0]+=dp[i-1][j][0])%=Mod; } } } } rep(i,0,L) (ans+=dp[N][i][1])%=Mod; printf("%d ",ans); return 0; }