1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4685 Solved: 2916
[ Submit][ Status][ Discuss]
Description
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为
0
Input
第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
111
Sample Output
【分析】
原本想数位dp,不知道可不可以,不过n的范围........
不看题解不会做,不过还是收获很大。这个题能将矩阵,kmp,dp结合起来,强____*
不吉利串是可以有重复子段的,这个需要KMP的失配函数处理。比如123123,失配函数f[]={0,0,0,0,1,2}
设dp[i][j]表示,前 i 位匹配到 j 位不吉利数字。
由dp[i][j]可以推出dp[i+1][k] (k是 j位数匹配时,可以匹配的短一点的位数)
这样推很麻烦,反过来推,dp[i][j]可以由dp[i-1][k]推出 (k位数失配时,可以倒退到匹配成功 j 个位)
设g[i][j]表示短串 i 位在长串上失配时,可以倒退到匹配成功 j 位的方案数。需要枚举长串当前位置的数字0~9来打g的表。
那么dp[i][j] = sum{ dp[i-1][k]*g[k][j] }(k从0到m-1,k等于m时意味着匹配到了一个短串,故不能记为答案)
这样可以由dp[0][j]递推出dp[n][j] (j是长串位数,从0到n-1)
但是n太大了,Fortunately,递推式恰好满足矩阵乘法原则:
dp[n] = dp[1] * (矩阵g的n次幂)
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int mod=1e9+7;
/************** matrix ********************/
struct matrix{
ll a[21][21]; //begin with 0
int r,c;
matrix(int n,int m):r(n),c(m){memset(a,0,sizeof(a));}
ll* operator[](int x){return a[x];}
friend matrix operator*(matrix A,matrix B)
{
matrix C(A.r,B.c);
for(int i=0;i<A.r;i++)
for(int j=0;j<B.c;j++)
for(int k=0;k<=A.c;k++){
C[i][j]+=(A[i][k]*B[k][j])%mod;
C[i][j]+=mod;
C[i][j]%=mod;
}
return C;
}
};
matrix qpow(matrix A,ll m)//方阵A的m次幂
{
matrix ans(A.r,A.c);
for(int i=0;i<A.r;i++) ans.a[i][i]=1;//单位矩阵
while(m)
{
if(m%2)ans=ans*A;
A=A*A;
m/=2;
}
return ans;
}
/************** kmp ********************/
int f[25]; //失配函数
void getfail(char *p)
{
f[0]=f[1]=0;
int n=strlen(p);
for(int i=1;i<n;i++)
{
int j=f[i];
while(j&&p[j]!=p[i])j=f[j];
if(p[j]==p[i])f[i+1]=j+1;
else f[i+1]=0;
}
}
/**************** solve *****************/
///dp[i][j]表前i位匹配上j位的种数 dp[0][0]=1;
int main()
{
int n,m,k;
char s[30];
scanf("%d%d%d%s",&n,&m,&mod,s);
getfail(s);
matrix g(m,m); //g[i][j] i位失配时匹配上j个位的种数
for(int i=0;i<m;i++)
{
for(int ch='0';ch<='9';ch++) //枚举当前位,失配到k
{
int k=i;
while(k&&s[k]!=ch)k=f[k];
if(s[k]==ch)k++;
if(k<m)//不完全匹配
g[i][k]++;
}
}
matrix dp(1,m);
dp[0][0]=1;
dp=dp*qpow(g,n);
ll ans=0;
for(int i=0;i<m;i++)ans=(ans+dp[0][i])%mod;
cout<<ans<<endl;
}