poj--2778DNA Sequence+AC自動機+矩陣快速冪
題目連結:點選進入
如果我們先將所有的病毒字串構建成一棵trie,然後構建一個n長的字串的過程可以看成是從這顆trie樹根節點出發走n步的一個過程,為了不含任何的病毒,則在走的過程中不能經過任何的病毒節點。考慮只走一步的過程,則我們可以得到一個矩陣m[i][j],表示從節點i到節點j有多少種方式。那麼這個矩陣的n次冪就是表示走n步的情況,然後也就可以得到答案了。
問題在於如何獲得這個走一步方案數的矩陣,我們可以利用構造ac自動機的過程,將所有的病毒葉子節點以及以這些節點做字尾的節點標記為病毒節點,然後就可以通過檢查每個節點的所有兒子節點得到到達他們的方案數了。更具體的思路見程式碼
程式碼如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
struct Matrix
{
ll mat[140][140];
int n;
Matrix(){};
Matrix(int n1)
{
n=n1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
mat[i][j]=0;
}
Matrix operator *(const Matrix &b) const
{
Matrix ret=Matrix(n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
ret.mat[i][j]+=mat[i][k]*b.mat[k][j];
ret.mat[i][j]%=100000;
}
return ret;
}
};
Matrix matrixPow(Matrix matrix,int n)
{
Matrix ret = Matrix(matrix.n);
for(int i=0;i<matrix.n;i++)
ret.mat[i][i]=1;
while(n)
{
if(n&1) ret=ret*matrix;
matrix=matrix*matrix;
n=n>>1;
}
return ret;
}
int getIndex(char x)
{
if(x=='A') return 0;
if(x=='T') return 1;
if(x=='C') return 2;
if(x=='G') return 3;
}
struct Trie
{
int next[140][4],fail[140],flag[140];
int root,L;
int newnode()
{
memset(next[L],-1,sizeof(next[L]));
flag[L++]=0;
return L-1;
}
void init()
{
L=0;
root=newnode();
}
void insert(char buf[])
{
int len=strlen(buf);
int now=root;
for(int i=0;i<len;i++)
{
int index=getIndex(buf[i]);
if(next[now][index]==-1)
next[now][index]=newnode();
now=next[now][index];
}
flag[now]++;
}
void build()
{
queue<int>Q;
fail[root]=root;
for(int i=0;i<4;i++)
{
if(next[root][i]==-1)
next[root][i]=root;
else
{
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
}
while(!Q.empty())
{
int now=Q.front();
Q.pop();
///如果當前字串的字尾節點是病毒,則當前字串也是病毒
///這是因為更新的時候會先更新淺層的然後再更新深層的
///所以要用淺層的標記去更新深層的
if(flag[fail[now]])
flag[now]++;
for(int i=0;i<4;i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
///獲得對應的狀態轉移矩陣
///對trie中的每個節點都檢查其所有兒子節點
void getMatrix(Matrix &matrix)
{
for(int i=0;i<L;i++)
for(int j=0;j<4;j++)
if(!flag[i]&&!flag[next[i][j]])
matrix.mat[i][next[i][j]]++;
}
};
Trie ac;
char str[20];
int main()
{
int m,n;
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&m,&n)!=EOF)
{
Matrix matrix = Matrix(50);
ac.init();
for(int i=0;i<m;i++)
{
scanf("%s",str);
ac.insert(str);
}
ac.build();
ac.getMatrix(matrix);
matrix=matrixPow(matrix,n);
ll ans=0;
//check(matrix);
for(int i=0;i<ac.L;i++)
ans+=matrix.mat[0][i];
printf("%lld\n",ans%100000);
}
return 0;
}
相關文章
- 矩陣快速冪矩陣
- 矩陣快速冪總結矩陣
- 矩陣快速冪(快忘了)矩陣
- 矩陣快速冪加速最短路矩陣
- 矩陣快速冪最佳化矩陣
- 【矩陣乘法】【快速冪】遞推矩陣
- 演算法學習:矩陣快速冪/矩陣加速演算法矩陣
- HDU 1005 Number Sequence(矩陣快速冪)矩陣
- POJ 3613 Cow Relays 矩陣乘法Floyd+矩陣快速冪矩陣
- HDU 2256Problem of Precision(矩陣快速冪)矩陣
- HDU 2157 How many ways?? (矩陣快速冪)矩陣
- BZOJ 3329 Xorequ:數位dp + 矩陣快速冪矩陣
- HDU 2276 - Kiki & Little Kiki 2 (矩陣快速冪)矩陣
- 從斐波那契到矩陣快速冪矩陣
- 第?課——基於矩陣快速冪的遞推解法矩陣
- 費馬小定理 + 費馬大定理 + 勾股數的求解 + 快速冪 + 矩陣快速冪 【模板】矩陣
- bzoj4887: [Tjoi2017]可樂(矩陣乘法+快速冪)矩陣
- BZOJ3329: Xorequ(二進位制數位dp 矩陣快速冪)矩陣
- POJ 3233 Matrix Power Series (矩陣快速冪+等比數列二分求和)矩陣
- HDU 4549 M斐波那契數列(矩陣快速冪+費馬小定理)矩陣
- 隨機矩陣隨機矩陣
- 自媒體矩陣怎麼打造?自媒體矩陣有什麼優勢?矩陣
- 快速冪
- 快速乘/快速冪
- 機器學習中的矩陣向量求導(五) 矩陣對矩陣的求導機器學習矩陣求導
- NYOJ 1409 快速計算【矩陣連乘】矩陣
- 巨大的矩陣(矩陣加速)矩陣
- 鄰接矩陣、度矩陣矩陣
- 快速冪模板
- 奇異矩陣,非奇異矩陣,偽逆矩陣矩陣
- 自媒體矩陣運營是什麼意思?自媒體矩陣應該怎麼運營?矩陣
- 資料結構:陣列,稀疏矩陣,矩陣的壓縮。應用:矩陣的轉置,矩陣相乘資料結構陣列矩陣
- 矩陣矩陣
- 越獄(快速冪)
- 求任意矩陣的伴隨矩陣矩陣
- 趣頭條矩陣運營助手,分發多個自媒體賬號,教你玩自媒體矩陣矩陣
- 動態dp & 矩陣加速遞推矩陣
- 矩陣和陣列矩陣陣列