版权声明:http://blog.csdn.net/Mitsuha_。 https://blog.csdn.net/Mitsuha_/article/details/82112834
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个数字字符串S,如果一个数字字符串(只包含0-9,可以有前导0)中出现且只出现1次S,我们就称这个字符串是好的。
例如假设S=666,则1666、03660666是好的,6666、66、123不是好的;假设S=1212,则01212、12123是好的,121212、121是不好的。
请你计算长度为N的数字字符串中,有多少个是好的。由于总数可能很大,你只需要输出总数模1000000007的余数。
输入
一个整数N和一个数字串S。
对于30%的数据,1 ≤ N ≤ 8
对于100%的数据,1 ≤ N ≤ 1000,1 ≤ |S| ≤ N。
输出
一个整数代表答案。
样例输入
6 1212
样例输出
298
思路:CF-1015F的基础上做了些改变。
但思路不变,还是DP+KMP。
表示构造了长度为 的数字串,其中以 为结尾匹配的长度是 , 表示该串已经(还未)出现过匹配的方案数。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e3+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
char s[MAX];
int f[MAX];
int d[MAX][MAX][2];
void getfail()
{
int n=strlen(s);
f[0]=f[1]=0;
for(int i=1;i<n;i++)
{
int j=f[i];
while(j&&s[i]!=s[j])j=f[j];
f[i+1]=(s[i]==s[j]?j+1:0);
}
}
int main()
{
int n;
scanf("%d%s",&n,s);
getfail();
int m=strlen(s);
d[0][0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(j<m)
{
for(int k=0;k<=9;k++)
{
if(k==s[j]-'0')//当前字符匹配
{
(d[i][j+1][0]+=d[i-1][j][0])%=MOD; //一次都未匹配的串
if(j+1<m)(d[i][j+1][1]+=d[i-1][j][1])%=MOD;//已经匹配过的串
}
else//当前字符不匹配,利用nex数组转移
{
int nex=j;
while(nex&&s[nex]!=k+'0')nex=f[nex];
if(s[nex]==k+'0')nex++;
(d[i][nex][0]+=d[i-1][j][0])%=MOD;
(d[i][nex][1]+=d[i-1][j][1])%=MOD;
}
}
}
if(j==m)
{
for(int k=0;k<=9;k++)//对d[i-1][m][0]做转移,即对刚匹配完的串做转移
{
int nex=m;
while(nex&&s[nex]!=k+'0')nex=f[nex];
if(s[nex]==k+'0')nex++;
if(nex==m)continue;
(d[i][nex][1]+=d[i-1][m][0])%=MOD;
}
}
}
}
int ans=d[n][m][0];
for(int i=0;i<m;i++)(ans+=d[n][i][1])%=MOD;
cout<<ans<<endl;
return 0;
}