版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/zzk_233/article/details/82852615
我的算法和大部分的题解算法有些不同。。。。算法来源参照http://acm.hdu.edu.cn/showproblem.php?pid=3689
那么这道题的思想可以转为求,当准考证号的长度为i时不吉利数字匹配的长度为j,那么设f[i][j]表示当前状态的方案数,则有转移
f[i][kmp(j-1,k)]+=f[i-1][j-1];
j为长度,因为kmp是从0开始的,所以他的位置为j-1,即求出下一个字符为k时的匹配位置。那么最后求出 即可
暴力代码
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
char ss[25];
int nxt[25],l;
int f[1005][25];
void gett()
{
int t1=0,t2=-1;
nxt[0]=-1;
while(t1<l)
{
if(t2==-1||ss[t1]==ss[t2])
{
t1++,t2++;
nxt[t1]=t2;
}else
{
t2=nxt[t2];
}
}
}
int kmp(int q,int w)
{
while((q!=-1)&&((ss[q]-'0')!=w))
{
q=nxt[q];
}
return q+1;
}
int main()
{
int n,m,K;
scanf("%d%d%d",&n,&m,&K);
scanf("%s",ss);
l=strlen(ss);
gett();
f[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=l;j++)
{
for(int k=0;k<=9;k++)
{
f[i][kmp(j-1,k)]+=f[i-1][j-1]%K;
f[i][kmp(j-1,k)]%=K;
}
}
}
int ans=0;
for(int j=0;j<l;j++)
{
ans+=f[n][j];
ans%=K;
}
printf("%d",ans);
return 0;
}
而我们发现每次转移的kmp都是固定的,所以可以矩阵乘法求出。
代码
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
char ss[25];
int nxt[25],l;
int n,m,K;
void gett()
{
int t1=0,t2=-1;
nxt[0]=-1;
while(t1<l)
{
if(t2==-1||ss[t1]==ss[t2])
{
t1++,t2++;
nxt[t1]=t2;
}else
{
t2=nxt[t2];
}
}
}
int kmp(int q,int w)
{
while((q!=-1)&&((ss[q]-'0')!=w))
{
q=nxt[q];
}
return q+1;
}
struct node
{
int f[30][30];
}dp,zy;
node operator *(node a,node b)
{
node ans1;
memset(ans1.f,0,sizeof(ans1.f));
for(int i=0;i<=25;i++)
{
for(int j=0;j<=25;j++)
{
for(int k=0;k<=25;k++)
{
ans1.f[i][j]+=a.f[i][k]*b.f[k][j]%K;
ans1.f[i][j]%=K;
}
}
}
return ans1;
}
void ksm(node a,int b)
{
while(b)
{
if(b%2==1)
{
dp=a*dp;
}
b=b/2;
a=a*a;
}
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
scanf("%s",ss);
l=strlen(ss);
gett();
for(int j=1;j<=l;j++)
{
for(int k=0;k<=9;k++)
{
zy.f[kmp(j-1,k)][j-1]++;
}
}
dp.f[0][0]=1;
ksm(zy,n);
int ans=0;
for(int i=0;i<l;i++)
{
ans+=dp.f[i][0];
ans%=K;
}
printf("%d",ans);
return 0;
}