• 题解 poj2778 DNA Sequence


    题解 poj2778 DNA Sequence

    题面

    poj

    解析

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

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

    先看 (l=2) 的情况:根据矩阵乘法有 (f_{i,j}=sumlimits_{k=1}^n f_{i,k} imes 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
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    100个高质量Java开发者博客
    javascript的trigger事件
    js正则函数match、exec、test、search、replace、split使用集合
    Openssl verify命令
    Openssl x509命令
    Openssl req命令
    Openssl asn1parse命令
    Openssl ec命令
    Openssl ecparam命令
    Openssl rsa命令
  • 原文地址:https://www.cnblogs.com/permzf/p/13138268.html
Copyright © 2020-2023  润新知