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

http://acm.hdu.edu.cn/showproblem.php?pid=2243

题意:

给出m个模式串,求长度不超过n的且至少包含一个模式串的字符串个数。

思路:

如果做过poj2778的话,那么这题相对来说就会容易一些。

如果直接去计算的话,情况很复杂,和poj2778一样,我们先求出不包含模式串的个数,最后只需要相减就可以。

因为这道题目长度只要不超过n就可以,所以在构造矩阵的时候需要多加一列,该列值每行全设为1(这样最后一列的值就是对上一个矩阵每一行的和,完美计算了了各种长度的个数之和)。最后得到的值res-1就是不包含的情况个数(减去1是因为一开始的时候多算了1)。

接下来计算一下所有情况的个数,$f(n)=1+26^1+26^2+...+26^n$,可以得出$f(n)=26*f(n-1)+1$,于是这就能构造出一个矩阵了,最后得到的res-1就是所有的情况个数。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11 using namespace std;
 12 typedef long long ll;
 13 const int INF = 0x3f3f3f3f;
 14 const int maxn=10000+5;
 15
 16 int n, m, num;
 17 char s[20];
 18
 19 struct Trie
 20 {
 21     int son[30];
 22     int cnt;
 23     int fail;
 24 }t[100];
 25
 26 struct Matrix
 27 {
 28     unsigned long long mat[40][40], n;
 29     Matrix(){}
 30     Matrix(int _n)
 31     {
 32         n=_n;
 33         for(int i=0;i<n;i++)
 34         for(int j=0;j<n;j++)
 35             mat[i][j]=0;
 36     }
 37     Matrix operator*(const Matrix& b) const
 38     {
 39         Matrix c=Matrix(n);
 40         for(int i=0;i<n;i++)
 41         {
 42             for(int j=0;j<n;j++)
 43             {
 44                 for(int k=0;k<n;k++)
 45                 {
 46                     c.mat[i][j]+=mat[i][k]*b.mat[k][j];
 47                 }
 48             }
 49         }
 50         return c;
 51     }
 52 };
 53
 54 void init(int x)
 55 {
 56     t[x].fail=0;
 57     t[x].cnt=0;
 58     memset(t[x].son,0,sizeof(t[x].son));
 59 }
 60
 61 void trie(char *s)
 62 {
 63     int n=strlen(s);
 64     int x=0;
 65     for(int i=0;i<n;i++)
 66     {
 67         int c=s[i]-‘a‘+1;
 68         if(!t[x].son[c])
 69         {
 70             num++;
 71             init(num);
 72             t[x].son[c]=num;
 73         }
 74         x=t[x].son[c];
 75     }
 76     t[x].cnt=1;
 77 }
 78
 79 void buildAC()
 80 {
 81     queue<int> Q;
 82     for(int i=1;i<=26;i++)  if(t[0].son[i])  Q.push(t[0].son[i]);
 83     while(!Q.empty())
 84     {
 85         int x=Q.front(); Q.pop();
 86         int fail=t[x].fail;
 87         for(int i=1;i<=26;i++)
 88         {
 89
 90             int y=t[x].son[i];
 91             if(y)
 92             {
 93                 t[y].fail=t[fail].son[i];
 94                 t[y].cnt|=t[t[fail].son[i]].cnt;  //这儿很重要,这个标记需要传递
 95                 Q.push(y);
 96             }
 97             else t[x].son[i]=t[fail].son[i];
 98         }
 99     }
100 }
101
102 Matrix getMatrix()
103 {
104     Matrix c=Matrix(num+2);
105     for(int i=0;i<=num;i++)
106     {
107         for(int j=1;j<=26;j++)
108         {
109             if(t[t[i].son[j]].cnt==0)  c.mat[i][t[i].son[j]]++;
110         }
111     }
112     for(int i=0; i<num+2; i++)  c.mat[i][num+1]=1;
113     return c;
114 }
115
116
117 Matrix q_pow(Matrix base, int n)
118 {
119     Matrix ans=Matrix(base.n);
120     for(int i=0;i<ans.n;i++)   ans.mat[i][i]=1;
121     while(n)
122     {
123         if(n&1)  ans=ans*base;
124         base=base*base;
125         n>>=1;
126     }
127     return ans;
128 }
129
130 int main()
131 {
132     //freopen("in.txt","r",stdin);
133     while(~scanf("%d%d",&m,&n))
134     {
135         init(0);
136         num=0;
137         for(int i=1;i<=m;i++)
138         {
139             scanf("%s",s);
140             trie(s);
141         }
142         buildAC();
143         Matrix c=getMatrix();
144         c = q_pow(c,n);
145         unsigned long long res = 0;
146         for(int i=0;i<c.n;i++) res+=c.mat[0][i];
147         res--;
148         c=Matrix(2);
149         c.mat[0][0]=26;
150         c.mat[0][1]=c.mat[1][1]=1;
151         c=q_pow(c,n);
152         unsigned long long ans=c.mat[0][0]+c.mat[0][1];
153         ans--;
154         ans-=res;
155         cout<<ans<<endl;
156     }
157     return 0;
158 }
时间: 2024-12-19 19:01:44

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自动机+矩阵快速幂)

和前几天做的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 #

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自己主动机+矩阵)

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