P3193 [HNOI2008]GT考试
题意
给定数字串 A[1..m]
构造一个数字串 X[1..n],使得串中不出现数字串 A
求出方案数模 k 的结果 n≤10^9 ,m≤20,k≤1000
分析
设答案为f[][].
f[i][j]表示当前X是在1-i时,匹配到A的第j个数字.
如果i+1选择的数字=A[j+1],那么就直接转移.
否则转移到f[i+1][next[j]+1].
对于A的每一个位置,每一次转移的方案数都是一定的.
所以可以直接跑一个矩阵,在乘上n次幂就可以了.
矩阵a[i][j]表示从第j位开始构造,最后匹配到第i位的方案数.此处i是下一个应该匹配的.
eg:如果i==m,那么就相当于我刚刚匹配的是第m-1位,匹配成功了,但是还没有匹配m,也是一个方案.
代码
#include<bits/stdc++.h>
using namespace std;
const int N=104;
int n,m,p,nex[N];
char s[N];
struct Kano{
int a[20][20];
Kano(){
memset(a,0,sizeof a);
}
void get(){
for(int i=0;i<m;i++)
a[i][i]=1;
}
Kano operator*(const Kano &b)const{
Kano c;
for(int k=0;k<m;k++)
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
c.a[i][j]+=a[i][k]*b.a[k][j],c.a[i][j]%=p;
return c;
}
}kano,f;
void kmp(){
int j=0;
for(int i=1;i<m;i++){
while(j&&s[i]!=s[j]) j=nex[j];
if(s[i]==s[j]) j++;
nex[i+1]=j;
}
}
Kano ksm(int x){
if(x==1)
return kano;
Kano t=ksm(x>>1);
t=t*t;
if(x&1)
t=t*kano;
return t;
}
int main(){
std::ios::sync_with_stdio(false);
cin>>n>>m>>p>>s;
kmp();
for(int i=0;i<m;i++)
for(int ch='0';ch<='9';ch++){
int j=i;
while(j&&s[j]!=ch) j=nex[j];
if(s[j]==ch) j++;
if(j!=m)
kano.a[j][i]++;
}
/*Kano k=kano*kano;
for(int i=0;i<m;++i){
for(int j=0;j<m;++j)
printf("%d",k.a[i][j]);
printf("\n");
}*/
f.a[0][0]=1;
f=ksm(n)*f;
int ans=0;
for(int i=0;i<m;i++)
ans=(ans+f.a[i][0])%p;
cout<<ans;
}
作者:${\color{Violet}かの}$
-----若转载请附原作者名及原文链接-----
-----若转载请附原作者名及原文链接-----