题解 poj2778 DNA Sequence

题解 poj2778 DNA Sequence

题面

poj

解析

先考虑这样一个问题:给定一个图\((n<=100)\),问从 \(s\)\(t\) 的长度为 \(l\) 的路径数是多少.

把邻接矩阵建出来,设为 \(x\),答案即为 \(x^l\) 的对应位置.

先看 \(l=2\) 的情况:根据矩阵乘法有 \(f_{i,j}=\sum\limits_{k=1}^n f_{i,k}\times f_{k,j}\)

即枚举中间点 \(k\),将方案数加起来.

其它的也是类似的道理.

那么回到题目:考虑一个字符串在 AC自动机 上的匹配,

那答案实际上就是从根到某个节点的长度为 \(n\) 的路径方案数.

把 AC 自动机建出来,处理出邻接矩阵,

但要注意如果 \(j\) 被标记,邻接矩阵中 \(f_{i,j}=0\).

矩阵快速幂处理即可.

code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define ll long long
using namespace std;

inline ll read(){
	ll sum=0,f=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0'){sum=sum*10+c-'0';c=getchar();}
	return f*sum;
}

const int N=101;
const int Mod=100000;
struct mat{
	ll f[N][N];
	mat(){memset(f,0,sizeof(f));}
	inline void init(){for(int i=0;i<N;i++) f[i][i]=1;}
};
ll n,m;
int ch[N][5],tot;
int fail[N],v[N];
char ss[N];
queue<int> que;

inline mat operator*(mat a,mat b){
	mat c;
	memset(c.f,0,sizeof(c.f));
	for(int i=0;i<N;i++){
		for(int k=0;k<N;k++){
			ll ret=a.f[i][k];if(!ret) continue;
			for(int j=0;j<N;j++){
				if(!b.f[k][j]) continue;
				c.f[i][j]=(c.f[i][j]+ret*b.f[k][j]%Mod)%Mod;
			}
		}
	}
	return c;
}

inline mat fpow(mat a,ll b){
	mat ret;ret.init();
	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++) ret.f[i][j]=(i==j);
	while(b){if(b&1) ret=ret*a;a=a*a;b>>=1;}
	return ret;
}

inline int id(char c){
	if(c=='A') return 0;
	if(c=='C') return 1;
	if(c=='T') return 2;
	if(c=='G') return 3;
}

inline void insert(char *s){
	int len=strlen(s);
	int p=0;
	for(int i=0;i<len;i++){
		int c=id(s[i]);
		if(!ch[p][c]) ch[p][c]=++tot,memset(ch[tot],0,sizeof(ch[tot]));
		p=ch[p][c];
	}
	v[p]=1;
}

inline void build(){
	for(int i=0;i<=3;i++)
		if(ch[0][i]) que.push(ch[0][i]),fail[ch[0][i]]=0;
	while(!que.empty()){
		int x=que.front();que.pop();
		v[x]|=v[fail[x]];
		for(int i=0;i<=3;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];
		}
	}
}

signed main(){
	m=read();n=read();
	for(int i=1;i<=m;i++){
		scanf("%s",ss);
		insert(ss);
	}
	build();mat a;
	for(int i=0;i<=tot;i++)
		for(int j=0;j<=3;j++){
			if(!v[ch[i][j]]) a.f[i][ch[i][j]]++;
		}
	a=fpow(a,n);		
	ll ans=0;
	for(int i=0;i<=tot;i++) ans=(ans+a.f[0][i])%Mod;
	printf("%lld\n",ans);
	return 0;
}

posted @ 2020-06-15 22:25  permzf  阅读(156)  评论(0编辑  收藏  举报