HDU 2243 考研路茫茫――单词情结 ——(AC自动机+矩阵快速幂)

  和前几天做的AC自动机类似。

  思路简单但是代码200余行。。

  假设solve_sub(i)表示长度为i的不含危险单词的总数。

  最终答案为用总数(26^1+26^2+...+26^n)减去(solve_sub(1)+solve(2)+...+solve_sub(n))。前者构造f[i]=f[i-1]*26+26然后矩阵快速幂即可(当然也可以分治的方法)。后者即构造出dp矩阵p,然后计算(p^1+p^2+...+p^n),对其分治即可。

  代码如下:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #include <vector>
  5 #include <queue>
  6 #include <iostream>
  7 using namespace std;
  8 const int MAX_Tot = 30 + 5;
  9 const int mod = 100000;
 10 typedef unsigned long long ull;
 11
 12 int m,n;
 13
 14 struct matrix
 15 {
 16     ull e[MAX_Tot][MAX_Tot];
 17     int n,m;
 18     matrix() {}
 19     matrix(int _n,int _m): n(_n),m(_m) {memset(e,0,sizeof(e));}
 20     matrix operator * (const matrix &temp)const
 21     {
 22         matrix ret = matrix(n,temp.m);
 23         for(int i=1;i<=ret.n;i++)
 24         {
 25             for(int j=1;j<=ret.m;j++)
 26             {
 27                 for(int k=1;k<=m;k++)
 28                 {
 29                     ret.e[i][j] += e[i][k]*temp.e[k][j];
 30                 }
 31             }
 32         }
 33         return ret;
 34     }
 35     matrix operator + (const matrix &temp)const
 36     {
 37         matrix ret = matrix(n,m);
 38         for(int i=1;i<=n;i++)
 39         {
 40             for(int j=1;j<=m;j++)
 41             {
 42                 ret.e[i][j] += e[i][j]+temp.e[i][j];
 43             }
 44         }
 45         return ret;
 46     }
 47     void getE()
 48     {
 49         for(int i=1;i<=n;i++)
 50         {
 51             for(int j=1;j<=m;j++)
 52             {
 53                 e[i][j] = i==j?1:0;
 54             }
 55         }
 56     }
 57 };
 58
 59 matrix qpow(matrix temp,int x)
 60 {
 61     int sz = temp.n;
 62     matrix base = matrix(sz,sz);
 63     base.getE();
 64     while(x)
 65     {
 66         if(x & 1) base = base * temp;
 67         x >>= 1;
 68         temp = temp * temp;
 69     }
 70     return base;
 71 }
 72
 73 matrix solve(matrix a, int k)
 74 {
 75     if(k == 1) return a;
 76     int n = a.n;
 77     matrix temp = matrix(n,n);
 78     temp.getE();
 79     if(k & 1)
 80     {
 81         matrix ex = qpow(a,k);
 82         k--;
 83         temp = temp + qpow(a,k/2);
 84         return temp * solve(a,k/2) + ex;
 85     }
 86     else
 87     {
 88         temp = temp + qpow(a,k/2);
 89         return temp * solve(a,k/2);
 90     }
 91 }
 92
 93 struct Aho
 94 {
 95     struct state
 96     {
 97         int nxt[26];
 98         int fail,cnt;
 99     }stateTable[MAX_Tot];
100
101     int size;
102
103     queue<int> que;
104
105     void init()
106     {
107         while(que.size()) que.pop();
108         for(int i=0;i<MAX_Tot;i++)
109         {
110             memset(stateTable[i].nxt,0,sizeof(stateTable[i].nxt));
111             stateTable[i].fail = stateTable[i].cnt = 0;
112         }
113         size = 1;
114     }
115
116     void insert(char *s)
117     {
118         int n = strlen(s);
119         int now = 0;
120         for(int i=0;i<n;i++)
121         {
122             char c = s[i];
123             if(!stateTable[now].nxt[c-‘a‘])
124                 stateTable[now].nxt[c-‘a‘] = size++;
125             now = stateTable[now].nxt[c-‘a‘];
126         }
127         stateTable[now].cnt = 1;
128     }
129
130     void build()
131     {
132         stateTable[0].fail = -1;
133         que.push(0);
134
135         while(que.size())
136         {
137             int u = que.front();que.pop();
138             for(int i=0;i<26;i++)
139             {
140                 if(stateTable[u].nxt[i])
141                 {
142                     if(u == 0) stateTable[stateTable[u].nxt[i]].fail = 0;
143                     else
144                     {
145                         int v = stateTable[u].fail;
146                         while(v != -1)
147                         {
148                             if(stateTable[v].nxt[i])
149                             {
150                                 stateTable[stateTable[u].nxt[i]].fail = stateTable[v].nxt[i];
151                                 // 在匹配fail指针的时候顺便更新cnt
152                                 if(stateTable[stateTable[stateTable[u].nxt[i]].fail].cnt == 1)
153                                     stateTable[stateTable[u].nxt[i]].cnt = 1;
154                                 break;
155                             }
156                             v = stateTable[v].fail;
157                         }
158                         if(v == -1) stateTable[stateTable[u].nxt[i]].fail = 0;
159                     }
160                     que.push(stateTable[u].nxt[i]);
161                 }
162                 /*****建立自动机nxt指针*****/
163                 else
164                 {
165                     if(u == 0) stateTable[u].nxt[i] = 0;
166                     else
167                     {
168                         int p = stateTable[u].fail;
169                         while(p != -1 && stateTable[p].nxt[i] == 0) p = stateTable[p].fail;
170                         if(p == -1) stateTable[u].nxt[i] = 0;
171                         else stateTable[u].nxt[i] = stateTable[p].nxt[i];
172                     }
173                 }
174                 /*****建立自动机nxt指针*****/
175             }
176         }
177     }
178
179     matrix build_matrix()
180     {
181         matrix ans = matrix(size,size);
182         for(int i=0;i<size;i++)
183         {
184             for(int j=0;j<26;j++)
185             {
186                 if(!stateTable[i].cnt && !stateTable[stateTable[i].nxt[j]].cnt)
187                     ans.e[i+1][stateTable[i].nxt[j]+1]++;
188             }
189         }
190         return ans;
191     }
192 }aho;
193
194 void print(matrix p)
195 {
196     int n = p.n;
197     int m = p.m;
198     for(int i=1;i<=n;i++)
199     {
200         for(int j=1;j<=m;j++)
201         {
202             printf("%d ",p.e[i][j]);
203         }
204         puts("");
205     }
206 }
207
208 int main()
209 {
210     while(scanf("%d%d",&m,&n) == 2)
211     {
212         aho.init();
213         char s[15];
214         for(int i=1;i<=m;i++)
215         {
216             scanf("%s",s);
217             aho.insert(s);
218         }
219         aho.build();
220         matrix p = aho.build_matrix();
221         p = solve(p,n);
222         ull temp = 0;
223         for(int i=1;i<=aho.size;i++) temp += p.e[1][i];
224         matrix t = matrix(1,2);
225         t.e[1][2] = 1;
226         matrix A = matrix(2,2);
227         A.e[1][1] = A.e[2][1] = 26; A.e[2][2] = 1;
228         t = t * qpow(A,n);
229         ull ans = t.e[1][1] - temp;
230         printf("%llu\n",ans);
231     }
232     return 0;
233 }

  最后觉得,,我之前矩阵模板里的print()真好用啊233= =。

时间: 2024-12-03 06:09:12

HDU 2243 考研路茫茫――单词情结 ——(AC自动机+矩阵快速幂)的相关文章

hdu 2243 考研路茫茫——单词情结 ac自动机+矩阵快速幂

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意:给定N(1<= N < 6)个长度不超过5的词根,问长度不超过L(L <231)的单词中至少含有一个词根的单词个数:结果mod 264. 基础:poj 2778DNA 序列求的是给定长度不含模式串的合法串的个数:串长度相当,都到了int上界了: 1.mod 264直接使用unsigned long long自然溢出即可:说的有些含蓄..并且也容易想到是直接使用内置类型,要不然高精度的

HDU 2243 考研路茫茫——单词情结(AC自动机+DP+快速幂)

题目链接 错的上头了... 这题是DNA的加强版,26^1 +26^2... - A^1-A^2... 先去学了矩阵的等比数列求和,学的是第二种方法,扩大矩阵的方法.剩下就是各种模板,各种套. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include &l

hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)

考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4843    Accepted Submission(s): 1527 Problem Description 背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了.一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如

HDU 2243 考研路茫茫――单词情结 (AC自动机 + dp)

HDU 2243 考研路茫茫――单词情结 题意:给定一些词根,如果一个单词包含有词根,则认为是有效的.现在问长度不超过L的单词里面,有多少有效的单词? 思路:这道题和POJ 2778是同样的思路.POJ 2778是要找出长度为L的单词里面有多少无效的单词.那么根据同样的方法构造矩阵,然后所有无效的单词个数为 A + A^2 + ... + A^l 个.而所有单词的个数为26 + 26^2 + - + 26^l 个.两个减一下即为答案. 矩阵连乘求和:I + A^2 + A^3 + ... + A

HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)

题目链接:考研路茫茫――单词情结 做本题前,个人建议先做一下POJ 2778 http://blog.csdn.net/u013446688/article/details/47378255 POJ2778 是求长度为n,不包含模式串的字符串个数. 而本题是求长度为n,包含模式串的字符串个数.直接用字符串总数减去不包含模式串的字符串个数即为所求. 同样是AC自动机 + 矩阵快速幂.但是还是有所不同的. 因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现

HDU 2243考研路茫茫——单词情结 (AC自动机+矩阵快速幂)

背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般表示"相反,变坏,离去"等. 于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢.更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义. 比如一共有2个词根 aa 和 ab ,则可能存在104个长度不

Hdu 2243 考研路茫茫——单词情结 (AC自动机+矩阵)

哎哟喂,中文题...不说题意了. 首先做过POJ 2778可以知道AC自动机是可以求出长度为L的串中不含病毒串的数量的. POJ 2778的大概思路就是先用所有给的病毒串建一个AC自动机,然后将AC自动机上所有非单词节点连一个边. 离散数学中有说道,如果矩阵A 中的 [i][j] 表示 i节点通过一条边可以走到j节点的方法数. 那么A*A这个矩阵的[i][j]就表示 i 节点到j 节点通过两条边可以走到j节点的方法数. 既然知道这个方法,我们就明确要求什么. ans= 26+26^2+26^3+

HDU 2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)

http://acm.hdu.edu.cn/showproblem.php?pid=2243 题意: 给出m个模式串,求长度不超过n的且至少包含一个模式串的字符串个数. 思路: 如果做过poj2778的话,那么这题相对来说就会容易一些. 如果直接去计算的话,情况很复杂,和poj2778一样,我们先求出不包含模式串的个数,最后只需要相减就可以. 因为这道题目长度只要不超过n就可以,所以在构造矩阵的时候需要多加一列,该列值每行全设为1(这样最后一列的值就是对上一个矩阵每一行的和,完美计算了了各种长度

Hdu 2243 考研路茫茫——单词情结 (AC自己主动机+矩阵)

哎哟喂.中文题. . .不说题意了. 首先做过POJ 2778能够知道AC自己主动机是能够求出长度为L的串中不含病毒串的数量的. POJ 2778的大概思路就是先用全部给的病毒串建一个AC自己主动机.然后将AC自己主动机上全部非单词节点连一个边. 离散数学中有说道.假设矩阵A 中的 [i][j] 表示 i节点通过一条边能够走到j节点的方法数. 那么A*A这个矩阵的[i][j]就表示 i 节点到j 节点通过两条边能够走到j节点的方法数. 既然知道这种方法.我们就明白要求什么. ans= 26+26