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

POJ2778一样。这题是求长度不超过n且包含至少一个词根的单词总数。

长度不超过n的单词总数记为Sn,长度不超过n不包含词根的单词总数记为Tn

答案就是,Sn-Tn

Sn=26+262+263+...+26n

Tn=A+A2+A3+...+An (A为AC自动机构造出来的矩阵)

可以构造矩阵用快速幂求出Sn和Tn

$$ \begin{bmatrix} 26 & 1 \\ 0 & 1 \end{bmatrix} \times \begin{bmatrix} S_n \\ 26 \end{bmatrix} = \begin{bmatrix} S_{n+1} \\ 26 \end{bmatrix}$$

$$ \begin{bmatrix} A & E \\ 0 & E \end{bmatrix} \times \begin{bmatrix} T_n \\ A \end{bmatrix} = \begin{bmatrix} T_{n+1} \\ A \end{bmatrix}$$

通过 $ \begin{bmatrix} 26 & 1 \\ 0 & 1 \end{bmatrix} ^n \times \begin{bmatrix} S_0 \\ 26 \end{bmatrix} = \begin{bmatrix} S_n \\ 26 \end{bmatrix}$ 即可得到Sn,其中S0=0,Tn同理。

另外题目结果mod 264这个直接把变量定义为unsigned __int64即可,溢出位数自动舍去。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 using namespace std;
  5 int tn,ch[33][26],fail[33];
  6 bool flag[33];
  7 void insert(char *s){
  8     int x=0;
  9     for(int i=0; s[i]; ++i){
 10         int y=s[i]-‘a‘;
 11         if(ch[x][y]==0) ch[x][y]=++tn;
 12         x=ch[x][y];
 13     }
 14     flag[x]=1;
 15 }
 16 void init(int x){
 17     memset(fail,0,sizeof(fail));
 18     queue<int> que;
 19     for(int i=0; i<26; ++i){
 20         if(ch[0][i]) que.push(ch[0][i]);
 21     }
 22     while(!que.empty()){
 23         int x=que.front(); que.pop();
 24         for(int i=0; i<26; ++i){
 25             if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i];
 26             else ch[x][i]=ch[fail[x]][i];
 27             flag[ch[x][i]]|=flag[ch[fail[x]][i]];
 28         }
 29     }
 30 }
 31 void init(){
 32     memset(fail,0,sizeof(fail));
 33     queue<int> que;
 34     for(int i=0; i<26; ++i){
 35         if(ch[0][i]) que.push(ch[0][i]);
 36     }
 37     while(!que.empty()){
 38         int now=que.front(); que.pop();
 39         for(int i=0; i<26; ++i){
 40             if(ch[now][i]) que.push(ch[now][i]),fail[ch[now][i]]=ch[fail[now]][i];
 41             else ch[now][i]=ch[fail[now]][i];
 42             flag[ch[now][i]]|=flag[ch[fail[now]][i]];
 43         }
 44     }
 45 }
 46 struct Mat{
 47     unsigned long long m[66][66];
 48     int n;
 49 };
 50 Mat operator*(const Mat &m1,const Mat &m2){
 51     Mat m={0};
 52     m.n=m1.n;
 53     for(int i=0; i<m.n; ++i){
 54         for(int j=0; j<m.n; ++j){
 55             for(int k=0; k<m.n; ++k) m.m[i][j]+=m1.m[i][k]*m2.m[k][j];
 56         }
 57     }
 58     return m;
 59 }
 60 int main(){
 61     int n,l;
 62     char str[6];
 63     while(~scanf("%d%d",&n,&l)){
 64         tn=0;
 65         memset(ch,0,sizeof(ch));
 66         memset(flag,0,sizeof(flag));
 67         while(n--){
 68             scanf("%s",str);
 69             insert(str);
 70         }
 71         init();
 72         Mat se={0},sm={0};
 73         se.n=sm.n=2;
 74         for(int i=0; i<2; ++i) se.m[i][i]=1;
 75         sm.m[0][0]=26; sm.m[0][1]=1; sm.m[1][1]=1;
 76         n=l;
 77         while(n){
 78             if(n&1) se=se*sm;
 79             sm=sm*sm;
 80             n>>=1;
 81         }
 82         unsigned long long tot=se.m[0][1]*26;
 83
 84         Mat te={0},tm={0};
 85         te.n=tm.n=tn+1<<1;
 86         for(int i=0; i<te.n; ++i) te.m[i][i]=1;
 87         for(int i=0; i<=tn; ++i){
 88             tm.m[i+tn+1][i+tn+1]=tm.m[i][i+tn+1]=1;
 89         }
 90         for(int i=0; i<=tn; ++i){
 91             if(flag[i]) continue;
 92             for(int j=0; j<26; ++j){
 93                 if(flag[ch[i][j]]) continue;
 94                 ++tm.m[i][ch[i][j]];
 95             }
 96         }
 97         Mat tmp=tm; tmp.n=tn+1;
 98         n=l;
 99         while(n){
100             if(n&1) te=te*tm;
101             tm=tm*tm;
102             n>>=1;
103         }
104         Mat tmp2; tmp2.n=tn+1;
105         for(int i=0; i<=tn; ++i){
106             for(int j=tn+1; j<te.n; ++j) tmp2.m[i][j-tn-1]=te.m[i][j];
107         }
108         tmp=tmp*tmp2;
109         unsigned long long res=0;
110         for(int i=0; i<=tn; ++i){
111             res+=tmp.m[0][i];
112         }
113         printf("%llu\n",tot-res);
114     }
115     return 0;
116 }
时间: 2024-10-10 04:07:34

HDU2243 考研路茫茫——单词情结(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自动机 + 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自动+矩阵)

考研路茫茫——单词情结 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在某本单词书上看到了一个根据词根来背单词的方法.比如

hdu2243考研路茫茫——单词情结

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

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

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

POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂

这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数. 题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的. 根据AC自动机的tire图,我们可以获得一个可达矩阵. 关于这题的tire图详解可以点击这里,往下面翻,这个博主的图对于tire图讲的非常详细. 知道了什么是tire图,理解了tire图后,后面的AC自动机的题目才能写. AC自动机的灵魂应该就是tire图 然后问题就变成了,得到了一个可达矩阵后,如何求方案数呢? 这个n = 2000000000 这咋办呢? 给定一

POJ POJ 2778 DNA Sequence AC自动机 + 矩阵快速幂

首先建立Trie和失败指针,然后你会发现对于每个节点 i 匹配AGCT时只有以下几种情况: i 节点有关于当前字符的儿子节点 j 且安全,则i 到 j找到一条长度为 1的路. i 节点有关于当前字符的儿子节点 j 且 不安全,则i 到 j没有路. i 节点没有关于当前字符的儿子节点 但是能通过失败指针找到一个安全的节点j,那么 i 到 j 找到一条长度为1的路. 关于节点安全的定义: 当前节点不是末节点且当前节点由失败指针指回跟节点的路径上不存在不安全节点,那么这个节点就是安全节点. 然后问题就