HDU2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)
2016-01-29 16:24
519 查看
与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即可,溢出位数自动舍去。
长度不超过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即可,溢出位数自动舍去。
#include<cstdio> #include<cstring> #include<queue> using namespace std; int tn,ch[33][26],fail[33]; bool flag[33]; void insert(char *s){ int x=0; for(int i=0; s[i]; ++i){ int y=s[i]-'a'; if(ch[x][y]==0) ch[x][y]=++tn; x=ch[x][y]; } flag[x]=1; } void init(int x){ memset(fail,0,sizeof(fail)); queue<int> que; for(int i=0; i<26; ++i){ if(ch[0][i]) que.push(ch[0][i]); } while(!que.empty()){ int x=que.front(); que.pop(); for(int i=0; i<26; ++i){ if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i]; else ch[x][i]=ch[fail[x]][i]; flag[ch[x][i]]|=flag[ch[fail[x]][i]]; } } } void init(){ memset(fail,0,sizeof(fail)); queue<int> que; for(int i=0; i<26; ++i){ if(ch[0][i]) que.push(ch[0][i]); } while(!que.empty()){ int now=que.front(); que.pop(); for(int i=0; i<26; ++i){ if(ch[now][i]) que.push(ch[now][i]),fail[ch[now][i]]=ch[fail[now]][i]; else ch[now][i]=ch[fail[now]][i]; flag[ch[now][i]]|=flag[ch[fail[now]][i]]; } } } struct Mat{ unsigned long long m[66][66]; int n; }; Mat operator*(const Mat &m1,const Mat &m2){ Mat m={0}; m.n=m1.n; for(int i=0; i<m.n; ++i){ for(int j=0; j<m.n; ++j){ for(int k=0; k<m.n; ++k) m.m[i][j]+=m1.m[i][k]*m2.m[k][j]; } } return m; } int main(){ int n,l; char str[6]; while(~scanf("%d%d",&n,&l)){ tn=0; memset(ch,0,sizeof(ch)); memset(flag,0,sizeof(flag)); while(n--){ scanf("%s",str); insert(str); } init(); Mat se={0},sm={0}; se.n=sm.n=2; for(int i=0; i<2; ++i) se.m[i][i]=1; sm.m[0][0]=26; sm.m[0][1]=1; sm.m[1][1]=1; n=l; while(n){ if(n&1) se=se*sm; sm=sm*sm; n>>=1; } unsigned long long tot=se.m[0][1]*26; Mat te={0},tm={0}; te.n=tm.n=tn+1<<1; for(int i=0; i<te.n; ++i) te.m[i][i]=1; for(int i=0; i<=tn; ++i){ tm.m[i+tn+1][i+tn+1]=tm.m[i][i+tn+1]=1; } for(int i=0; i<=tn; ++i){ if(flag[i]) continue; for(int j=0; j<26; ++j){ if(flag[ch[i][j]]) continue; ++tm.m[i][ch[i][j]]; } } Mat tmp=tm; tmp.n=tn+1; n=l; while(n){ if(n&1) te=te*tm; tm=tm*tm; n>>=1; } Mat tmp2; tmp2.n=tn+1; for(int i=0; i<=tn; ++i){ for(int j=tn+1; j<te.n; ++j) tmp2.m[i][j-tn-1]=te.m[i][j]; } tmp=tmp*tmp2; unsigned long long res=0; for(int i=0; i<=tn; ++i){ res+=tmp.m[0][i]; } printf("%llu\n",tot-res); } return 0; }
相关文章推荐
- TCP连接的建立和断开
- Icinga使用总结
- 调用css时,用link 和 @import url 有什么区别
- 解决 PermGen space Tomcat内存设置
- Ajax实例练习--股票动态更新面板
- 优化UITableViewCell高度计算的那些事
- Android之实现ViewPager+Fragment左右滑动
- lua解析脚本过程中的关键数据结构介绍
- iOS 学习日志 : git使用
- Scrapy如何借助于BloomFilter实现增量爬取
- linux下添加环境变量
- 2016流行这2种色彩!附优秀网页设计案例
- 一些小知识点的累积
- 链表(创建,插入,删除和打印输出(转载)
- json_decode() expects parameter 1 to be string, object given
- armhf sig bus error
- c#之类型转换2
- spark core源码分析4 worker启动流程
- Shell文件包含
- Shell输入输出重定向:Shell Here Document,/dev/null文件