POJ_2778 DNA Sequence AC自动机+dp
来源:互联网 发布:星际淘宝主 编辑:程序博客网 时间:2024/05/20 13:41
http://poj.org/problem?id=2778
题意:
给你M个最多只有10个字符的字符串,问长度为N的不含这些字符串的字符串的
个数有多少个。N<=2000000000,M<=10
思路:
字符串匹配的问题,用AC自动机是最好的选择,因为N的范围很大, 直觉告诉
我们要用二分矩阵乘法。接着就是列状态转移方程,用F(i , j )表示 i 个字符
的字符串,最后一个串的状态为j时候的种数,状态转移方程就可以表示为:
F(i ,j )= sum{ F( i-1 , j' ) },其中j'到j一个合法的转移。这样我们就可以转
换为矩阵相乘。具体的注释见代码吧。
代码:
#include<stdio.h>#include<string.h>#include<queue>const __int64 Mod = 100000 ;int N ,M, Root ,cnt ;char ch[20] ;struct Node{ int fail ; //AC自动机的失败指针 bool danger ; //标记以该结点为结尾的字符串是否合法 int next[4] ; //next数组 void init(){ //初始化各个变量 fail = -1 ; danger = 0 ; memset(next , -1 ,sizeof(next)); }}p[110] ;std::queue<int> que ;__int64 g[110][110] ; //g[i][j]表示由状态i转移到状态j的种数inline int get(char c){ switch(c){ case 'A' : return 0 ; case 'C' : return 1 ; case 'T' : return 2 ; case 'G' : return 3 ; default : return -1 ; }}void build_trie(char *ch){ int len = strlen(ch) ; int idx ,loc = Root; for(int i=0;i<len;i++){ idx = get(ch[i]) ; if( p[loc].next[idx] == -1 ){ ++cnt ; p[cnt].init() ; p[loc].next[idx] = cnt ; } loc = p[loc].next[idx] ; if( p[loc].danger ) return ; //如果当前字符串是前面某个字符串的前缀,则该字符串的接下去的状态都不合法 } p[loc].danger = 1 ; //最后的状态标记为不合法}void build_ac_automation(){ int loc = Root ; p[loc].fail = -1 ; while(!que.empty()) que.pop() ; que.push(loc) ; while(!que.empty()){ int u = que.front() ; que.pop() ; for(int i=0;i<4;i++){ if( p[u].next[i] == -1 ) continue ; int v = p[u].next[i] ; if( u==Root ){ p[v].fail = Root ; } else{ int temp = p[u].fail ; while( temp!= -1 ){ if( p[temp].next[i] != -1){ p[v].fail = p[temp].next[i] ; if( p[ p[temp].next[i] ].danger ){ //和普通的建失败指针唯一不同的地方,请注意。 p[v].danger = 1 ; } break ; } temp = p[temp].fail ; } if( temp == -1 ) p[v].fail = Root ; } que.push(v) ; } }}void cal(){ memset(g, 0,sizeof(g)); for(int i=0;i<=cnt;i++){ if( p[i].danger ) continue; for(int j=0;j<4;j++){ if( p[i].next[j]!=-1 && p[ p[i].next[j] ].danger==0){ g[i][ p[i].next[j] ] ++ ; } else if( p[i].next[j] == -1 ){ int temp = p[i].fail ; while( temp != -1 ){ if( p[temp].next[j] != -1 ){ break ; } temp = p[temp].fail ; } if(temp == -1) g[i][Root] ++ ; else{ if( p[ p[temp].next[j] ].danger == 0 ) g[i][ p[temp].next[j] ] ++ ; } } } }}__int64 res[110][110] ;void calc(__int64 a[110][110],__int64 b[110][110]){ __int64 c[110][110] ; for(int i=0;i<=cnt;i++){ for(int j=0;j<=cnt;j++){ c[i][j] = 0 ; for(int k=0;k<=cnt;k++){ c[i][j] = ( c[i][j] + a[i][k] * b[k][j] % Mod ) % Mod ; } } } for(int i=0;i<=cnt;i++) for(int j=0;j<=cnt;j++) a[i][j] = c[i][j] ;}void solve(int k){ while(k){ if( k & 1 ){ calc(res, g); } calc(g,g) ; k >>= 1 ; }}int main(){ Root = 0 ; while(scanf("%d%d",&M,&N) == 2){ p[Root].init() ; cnt = 0 ; for(int i=1;i<=M;i++){ scanf("%s",ch); build_trie(ch) ; //构建字典树 } build_ac_automation() ; cal() ; memset(res,0,sizeof(res)); for(int i=0;i<110;i++) res[i][i]= 1 ; solve(N) ; __int64 ans = 0 ; for(int i=0;i<=cnt;i++){ ans += res[0][i] ; if( ans > Mod ) ans %= Mod ; } printf("%I64d\n",ans); } return 0 ;}
- POJ_2778 DNA Sequence AC自动机+dp
- poj_2778 DNA Sequence(AC自动机+矩阵快速幂)
- POJ 2778 DNA Sequence (AC自动机 + dp)
- POJ2778 DNA Sequence AC自动机+DP+矩阵快速幂
- poj 2778 DNA Sequence 【ac自动机 + dp + 矩阵快速幂】
- POJ 2778 DNA Sequence AC自动机 矩阵加速DP
- POJ 2778 DNA Sequence(AC自动机+矩阵幂DP)
- [AC自动机+dp+矩阵快速幂] poj 2778 DNA Sequence
- POJ2778 DNA Sequence AC自动机,DP,矩阵加速
- POJ 2778 DNA Sequence AC自动机+DP+矩阵二分加速
- POJ 2778 DNA Sequence AC自动机DP的矩阵优化
- POJ2778 DNA Sequence AC自动机+快速幂+DP
- [POJ 2778] DNA Sequence (AC自动机+DP+矩阵加速)
- poj2778 DNA Sequence AC自动机 dp 矩阵乘法
- POJ 2778 DNA Sequence AC自动机+DP+快速幂
- POJ 2778 DNA Sequence(AC自动机+矩阵幂DP)
- POJ 2778 DNA Sequence(AC自动机+矩阵)
- POJ 2778 DNA Sequence (AC自动机)
- 程序员必知8大排序3大查找(一)
- BeanUtils.copyProperties()的用法
- [iOS] Xcode 4透過Ad-Hoc發佈App給其它裝置測試使用
- 程序员必知8大排序3大查找(二)
- 打开xls文件“格式与文件扩展名指定的格式不一致”错误的解决方法
- POJ_2778 DNA Sequence AC自动机+dp
- Android编译遇到错误/usr/bin/ld: cannot find -lstdc++的解决
- bitmap size exceeds VM budget
- 【ORACLE】Oracle 增加 修改 删除 列
- C# winform自定义Label控件使其能设置行距
- 让你的文字动起来——Marquee用法详解
- RPL保存在选择子里,那么CPL是保存在哪里的
- 现如今教育成为一个行为怪异的表现
- android 瀑布流效果