BZOJ 1009: [HNOI2008]GT考试
1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3434 Solved: 2109
[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
4 3 100
111
111
Sample Output
81
HINT
Source
分析:
我们可以想到这题可以用$DP$来完成,$f[i][j]$代表构造方案的第$i$个字符匹配上了不吉利数字的第$j$个字符的合法方案数,然后我们枚举下一位填哪个数字转移到哪里,如果我们枚举的数字$k$恰好匹配上了第$j+1$个不吉利数字,那么就可以转移到$f[i+1][j+1]$,否则我们就通过$kmp$来找到转移的状态...
发现不吉利数字的长度很小,方案数字的长度很大,所以可以用矩阵快速幂来优化转移...
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=20+5;
int n,m,mod,nxt[maxn];
char s[maxn];
struct Matrix{
int a[maxn][maxn];
inline void clear(void){
memset(a,0,sizeof(a));
}
friend Matrix operator * (Matrix x,Matrix y){
Matrix ans;ans.clear();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
(ans.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod)%=mod;
return ans;
}
inline Matrix power(Matrix M,int x){
Matrix ans;ans.clear();
for(int i=0;i<n;i++)
ans.a[i][i]=1;
while(x){
if(x&1)
ans=ans*M;
M=M*M,x>>=1;
}
return ans;
}
}G;
inline void getnxt(void){
nxt[0]=nxt[1]=0;int k;
for(int i=1;i<n;i++){
k=nxt[i];
while(k&&s[i+1]!=s[k+1])
k=nxt[k];
if(s[i+1]==s[k+1])
nxt[i+1]=k+1;
else
nxt[i+1]=0;
}
}
inline void getmatrix(void){
for(int i=0;i<n;i++)
for(int j=0,k;j<=9;j++){
k=i;
while(k&&(int)(s[k+1]-'0')!=j)
k=nxt[k];
if((int)(s[k+1]-'0')==j)
k++;
else
k=0;
G.a[i][k]++;
}
}
inline int solve(void){
G=G.power(G,m);
int ans=0;
for(int i=0;i<=n;i++)
(ans+=G.a[0][i])%=mod;
return ans;
}
signed main(void){
scanf("%d%d%d%s",&m,&n,&mod,s+1);G.clear();
getnxt();getmatrix();printf("%d\n",solve());
return 0;
}
By NeighThorn

浙公网安备 33010602011771号