[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

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     }
 
原文地址:https://www.cnblogs.com/noip/p/2962560.html