BZOJ 1009 GT考试
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位的数。 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
HINT
Source
利用“不吉利数字”构建ac自动机(我好像小题大做了,一个串好像没有必要),构建初始矩阵,接着矩阵乘法即可。
初始矩阵a[i][j]表示走一步从i节点走到j节点的方案数。
code:
1 #include<vector> 2 #include<queue> 3 #include<cstring> 4 #include<cstdio> 5 #include<cstdlib> 6 using namespace std; 7 8 #define maxm 25 9 char buf[maxm]; 10 int n,m,rhl,ans; 11 12 struct node 13 { 14 int a[maxm*maxm][maxm*maxm],n,m; 15 node() {memset(a,0,sizeof(a));n = m = 0;} 16 17 friend node operator *(node x,node y) 18 { 19 node z; z.n = x.n; z.m = y.m; 20 int i,j,k; 21 for (i = 1;i <= z.n;++i) 22 for (j = 1;j <= z.m;++j) 23 for (k = 1;k <= x.m;++k) 24 (z.a[i][j] += (long long)x.a[i][k]*(long long)y.a[k][j]%rhl)%=rhl; 25 return z; 26 } 27 28 inline node quick(node x,int k) 29 { 30 node ret; ret.n = x.n; ret.m = x.m; 31 for (int i = 1;i <= ret.n;++i) ret.a[i][i] = 1; 32 for (;k;k>>=1,x = x*x) 33 if (k & 1) 34 ret = ret*x; 35 return ret; 36 } 37 38 inline void calc() { for (int i = 0;i <= m;++i) (ans += a[1][i])%=rhl; } 39 }s; 40 41 struct trie 42 { 43 int next[maxm][10],fail[maxm],L,root; 44 bool end[maxm]; 45 inline int newnode() 46 { 47 memset(next[L],-1,sizeof(next[L])); 48 return ++L-1; 49 } 50 51 inline void init() {L = 0; root = newnode();} 52 53 inline void insert() 54 { 55 int len = strlen(buf),now = root,i; 56 for (i = 0;i < len;++i) 57 { 58 if (next[now][buf[i]-'0'] == -1) next[now][buf[i]-'0'] = newnode(); 59 now = next[now][buf[i]-'0']; 60 } 61 end[now] = true; 62 } 63 64 inline void build() 65 { 66 int now = root,i; queue <int> team; 67 fail[root] = root; 68 for (i = 0;i < 10;++i) 69 if (next[now][i] == -1) next[now][i] = root; 70 else fail[next[now][i]] = root,team.push(next[now][i]); 71 while (!team.empty()) 72 { 73 now = team.front(); team.pop(); 74 for (i = 0;i < 10;++i) 75 if (next[now][i] == -1) next[now][i] = next[fail[now]][i]; 76 else fail[next[now][i]] = next[fail[now]][i],team.push(next[now][i]); 77 } 78 } 79 80 inline void ready() 81 { 82 vector <int> son[maxm]; queue <int> team; int i,now,v,nn; 83 for (i = 0;i < L;++i) if (fail[i] != i) son[fail[i]].push_back(i); 84 team.push(root); 85 while (!team.empty()) 86 { 87 now = team.front(); team.pop(); 88 nn = son[now].size(); 89 for (i = 0;i < nn;++i) 90 { 91 v = son[now][i]; 92 if (end[now]) end[v] = true; 93 team.push(v); 94 } 95 } 96 } 97 98 inline void make() 99 { 100 int i,j; s.n = s.m = L; 101 for (i = 0;i < L;++i) 102 { 103 if (end[i]) continue; 104 for (j = 0;j < 10;++j) 105 if (!end[next[i][j]]) s.a[i+1][next[i][j]+1]++; 106 } 107 } 108 }ac; 109 110 int main() 111 { 112 freopen("1009.in","r",stdin); 113 freopen("1009.out","w",stdout); 114 scanf("%d %d %d\n",&n,&m,&rhl); 115 ac.init(); 116 scanf("%s",buf); ac.insert(); 117 ac.build(); ac.ready(); ac.make(); 118 s = s.quick(s,n); s.calc(); 119 printf("%d",ans); 120 fclose(stdin); fclose(stdout); 121 return 0; 122 }
高考结束,重新回归。