您的位置:首页 > 产品设计 > UI/UE

POJ 2778 DNA Sequence && AC自动机 矩阵 矩阵加速

2013-10-14 21:02 309 查看
暑假刚学完AC自动机模板的时候,看见这道题就感觉这题好难,经过几次复习与学习,突然发现这题不是那么的难。

题意:给你10个只由‘A’、‘T’、‘C’、‘G’这四个字母组成的最大长度为10的字符串。问有多少个不同的长度为n (1 <= n <=2000000000).的字符串。结果对100000取余。

解法:之前做的都是状压DP,见到这题也想这么做,突然发现长度略大,DP一定TLE。由于数据量是10^9,本能反应就是log(n)算法,看那众多大神的题解,学习到,原来矩阵也可以这么用。先是做一个AC自动机,然后做状态转移矩阵:枚举每一个节点,然后让这个节点添加一个字母(A、T、C、G)判断是不是单词节点,如果不是就把矩阵的对应位置++;如果是单词节点,那么就寻找适配路径之前的节点,同上处理。最后就能得到一个“节点数*节点数”大小的矩阵,每个位置代表从某个状态转移到另一个状态的方案数。最后求矩阵的n次方,需要矩阵加速,也就是快速幂的思路。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define pi acos(-1.0)
#define eps 1e-8
using namespace std;
const int maxnode = 110;
const int charsize = 4;
const int mod = 100000;
int ch[maxnode][charsize], f[maxnode], val[maxnode], last[maxnode];
int sz, n, m;

void init() {memset(ch[0],0,sizeof ch[0]);sz=1;}
int idx(char c) {if(c=='A') return 0; if(c=='T') return 1; if(c=='C') return 2; return 3;}
void insert(char *s, int v = 1)
{
int u = 0, n = strlen(s);
for(int i = 0 ; i < n ; ++ i)
{
int c = idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof ch[sz]);
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}

void getfail()
{
queue<int> q;
f[0] = 0;
for(int c = 0 ; c < charsize ; ++ c)
{
int u = ch[0][c];
if(u) {f[u]=last[u]=0;q.push(u);}
}
while(!q.empty())
{
int r = q.front(); q.pop();
for(int c = 0 ; c < charsize ; ++ c)
{
int u = ch[r][c];
if(!u) { ch[r][c] = ch[f[r]][c];continue;}
q.push(u);
int v = f[r];
while(v&&!ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]]?f[u]:last[f[u]];
}
}
}

struct mat
{
long long m[maxnode][maxnode];
mat operator*(const mat& ma) const
{
mat c;
memset(c.m, 0, sizeof c.m);
for(int i = 0 ; i < sz ; ++ i)
{
for(int j = 0 ; j < sz ; ++ j)
{
for(int k = 0 ; k < sz ; ++ k)
{
c.m[i][j] += m[i][k]*ma.m[k][j];
}
if(c.m[i][j]>=mod) c.m[i][j]%=mod;
}
}
return c;
}
}g;
mat pow(mat m, int n)
{
mat tmp;
for(int i = 0 ; i < sz ; ++ i)
{
for(int j = 0 ; j < sz ; ++ j)
{
tmp.m[i][j] = (i==j);
}
}

while(n)
{
if(n&1) tmp = tmp*m;
m = m*m;
n>>=1;
}
return tmp;
}

int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
char s[maxnode];
init();
for(int i = 0 ; i < n ; ++ i)
{
scanf("%s",s);
insert(s);
}
getfail();
for(int i = 0 ; i < sz ; ++ i)
{
if(val[i]||last[i]) continue;
for(int c = 0 ; c < charsize ; ++ c)
{
int u = ch[i][c];
if(u)
{
if(!val[u]&&!last[u]) g.m[i][u] ++;
}
else
{
int t = f[i];
while(t)
{
int u = ch[t][c];
if(u&&!val[u]&&!last[u])
{
g.m[i][u]++;
break;
}
t = f[t];
}
if(t==0)
{
int u = ch[t][c];
if(!u&&!val[u]&&!last[u]) g.m[i][u]++;
else if(!u) g.m[i][0]++;
}
}
}
}
mat tt = pow(g, m);
long long ans = 0;
for(int i = 0 ; i < sz ; ++ i)
{
ans += tt.m[0][i];
ans%=mod;
}
printf("%I64d\n",ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  AC自动机 矩阵