[HNOI2008]GT考试
Description
阿申准备报名参加GT考试,准考证号为N位数 X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。他的不吉利数学A1A2...Am(0<=Ai& lt;=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0
Input
第一行输入N,M,K.接下来一行输入M位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
4 3 100
111
111
Sample Output
81
神题碰上弱菜.....
动态规划啊,但数据这么大怎么想得到是动态规划呢,太弱了......
f[i][j]表示准考证前i位中后j位为不吉利的数字的前j位。
转移方程:
因此就可以使用矩阵乘法加速了!
a[k][j]表示f[i-1][k]转为f[i][j]的方法数,这步可以用KMP解决。
ans+=f[0][j] (j=0;j<m;++j);
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string.h> 5 #include<fstream> 6 using namespace std; 7 //ifstream fin("fin.in"); 8 9 string s; 10 int n,m,mod,ans=0,pi[25]; 11 int f[25][25]={0},a[25][25],b[25][25]; 12 13 void Work(int x){ 14 if(x>3) Work(x/2); 15 if(x==1) return ; 16 17 memset(a,0,sizeof(a)); 18 for(int i=0;i<m;++i) 19 for(int j=0;j<m;++j) 20 for(int k=0;k<m;++k) 21 a[i][j]=(a[i][j]+f[i][k]*f[k][j])%mod; 22 23 memcpy(f,a,sizeof(a)); 24 25 if(x%2) 26 { 27 memset(a,0,sizeof(a)); 28 for(int i=0;i<m;++i) 29 for(int j=0;j<m;++j) 30 for(int k=0;k<m;++k) 31 a[i][j]=(a[i][j]+f[i][k]*b[k][j])%mod; 32 33 memcpy(f,a,sizeof(f)); 34 } 35 } 36 37 void Kmp(){ 38 for(int i=2;i<s.size();++i) 39 { 40 int x=pi[i-1]; 41 while(s[i]!=s[x+1]&&x!=0) x=pi[x]; 42 if(s[i]==s[x+1]) pi[i]=x+1; 43 } 44 } 45 46 void Prepare(){ 47 for(int i=0;i<s.size()-1;++i) 48 for(int j=0;j<=9;++j) 49 { 50 int x=i; //小心观看 51 while(x!=0&&j!=s[x+1]-'0') x=pi[x]; 52 if(j==s[x+1]-'0') f[i][x+1]++; 53 else f[i][0]++; 54 } 55 memcpy(b,f,sizeof(f)); 56 } 57 58 int main() 59 { 60 cin>>n>>m>>mod>>s; 61 s=" "+s; 62 Kmp(); 63 64 Prepare(); 65 66 Work(n); 67 68 for(int i=0;i<m;++i) ans+=f[0][i]; 69 70 cout<<ans%mod<<endl; 71 // system("pause"); 72 return 0; 73 74 }