POJ 2778(DNA Sequence-Fail指针+矩阵快速幂)

在只有4个字母的字符集中,给你n个字符串(n*L<=100) ,求长度为m的且不包含前面任何一个序列的字符串个数(m<=2000000000)

建一个字典树,在上面加Fail指针
然后 goi,c 表示 从i点走字母 c 会到字典树上的哪个点
最后建立邻接矩阵A,ai,j表示从字典树上的节点 ij 的可行路径
预处理出字典树上的哪些节点会匹配字符串,删掉它们所在行、列
答案就是 Am root所在行的和

#include<cstdio>
#include<iostream>
#include<functional>
#include<vector>
#include<cstring>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--))  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000)
#define MAXN (100+10)
#define MAXNode (100+10)
#define Sigma_size (5)
#define pb push_back 
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
void upd(ll &a,ll b){a=(a%F+b%F)%F;}

ll pow2(ll a,ll b)
{
    if (b==1) return a;
    if (b==0) return 1;
    ll p=pow2(a,b/2)%F;
    p=p*p%F;
    if (b&1) p=p*a%F;
    return p;
}

struct M  
{  
    int n,m;  
    ll a[MAXN][MAXN];  
    M(int _n=0){n=m=_n;MEM(a);} 
    M(int _n,int _m){n=_n,m=_m;MEM(a);}
    void mem (int _n=0){n=m=_n;MEM(a);}
    void mem (int _n,int _m){n=_n,m=_m;MEM(a);}

    friend M operator*(M a,M b)  
    {  
        M c(a.n,b.m);  
        For(k,a.m)
            For(i,a.n)  
                For(j,b.m)  
                    c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%F;  
        return c;     
    }  
    void make_I(int _n)  
    {  
        n=m=_n; MEM(a)
        For(i,n) a[i][i]=1;  
    }  
}A;

int n;
ll m;
class Trie
{
public:
    int ch[MAXNode][Sigma_size],fa[MAXNode];
    int fail[MAXNode],go[MAXNode][Sigma_size];
    int siz;
    bool tag[MAXNode];
    void mem(){siz=0; MEM(tag) MEM(ch) MEM(fa) MEM(go) MEM(fail) }
    int idx(char c){return c=='A' ? 0 :c=='T' ? 1 :c=='C' ? 2 :3 ;}
    void insert(char *s)
    {
        int u=0,n=strlen(s);
        Rep(i,n)
        {
            int c=idx(s[i]);
            if (!ch[u][c])
            {
                ++siz;
                MEM(ch[siz]);
                ch[u][c]=siz;
                fa[siz]=u;
            }
            u=ch[u][c];
        }
        tag[u]=1;
    }
    int q[MAXNode+10];
    void make_fail()
    {
        int Head=1,Tail=1;
        q[Head]=0;
        For(i,siz) fail[i]=0;
        while(Head<=Tail) {
            int u=q[Head];
            Rep(c,4)
            {
                if (ch[u][c]) {
                    q[++Tail]=ch[u][c];
                    if (u==0) fail[ch[u][c]]=0;
                    else fail[ch[u][c]]=go[ fail[u] ][c];
                    go[u][c]=ch[u][c];
                }
                else {
                    go[u][c]=go[fail[u]][c];
                }
            } 
            Head++; 
        }
//      For(i,siz) cout<<fail[i]<<" ";cout<<endl;

        For(i,Tail) {
            int now=q[i];
            if (tag[fail[now]]) tag[now]=1;
        }

        int t=0;
        vector<int> Q;
        int h[MAXN]={0};
        Rep(i,siz+1) {
            if (!tag[i]) Q.pb(i),h[i]=++t;
        }
        A.mem(t);
        For(i,t)
        {
            int now=Q[i-1]; 
            Rep(j,4) {
                int v=go[now][j];
                if (h[v]) A.a[i][h[v]]++; 
            } 
        } 
//      For(i,t) {
//          For(j,t) cout<<A.a[i][j]<<' ';
//          cout<<endl;
//      }
    }
}T;

M pow2(M a,ll b)  
{  
    M c;c.make_I(a.n);    
    static bool a2[1000000];    
    int n=0;while (b) a2[++n]=b&1,b>>=1;    
    For(i,n)    
    {    
        if (a2[i]) c=c*a;    
        a=a*a;    
    }    
    return c;    
}
char s[20];
int main()
{
//  freopen("poj2778.in","r",stdin);
//  freopen(".out","w",stdout);
    cin>>n>>m;
    T.mem();
    For(i,n) {
        scanf("%s",s);
        T.insert(s);
    }
    T.make_fail();
    A=pow2(A,m);
    ll ans=0;
    For(i,A.n) upd(ans,A.a[1][i]);
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值