码迷,mamicode.com
首页 > 其他好文 > 详细

【OJ3446】copy

时间:2019-02-27 23:26:15      阅读:197      评论:0      收藏:0      [点我收藏+]

标签:lin   建立   math   题意   main   pen   turn   字典序   超过   

题意:

给你 \(n\) 个字符串,选每个字符串的一个子串依次拼在一起形成一个字符串 \(T\) 。按字典序输出所有可能的 \(T\) 并统计方案数。

(输入文件不超过 1 MB ,输出文件不超过 200 MB .)

题解:

对每个字符串都建立一个 SAM 。如果某个节点没有转移边,则连向右边 SAM (最靠左的)根的转移边指向的节点。

输出直接 dfs ,统计方案数直接拓扑序。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
const int N=3000005,M=7000005,Mod=1000000007;
int pre[N],len[N],ch[N][5],lst,cnt,rt[N],size[N];
int n,m[233],get[N],head[N],nxt[M],to[M],tot,in[N],pl[N],q[N];
char ans[N],h[5];
string s[N];
void extend(int r, int c)
{
    int p=lst,np=++cnt;lst=np;
    len[np]=len[p]+1,size[np]=1;
    for(;p&&!ch[p][c];p=pre[p]) ch[p][c]=np;
    if(!p) {
        pre[np]=r;
        return ;
    }
    int q=ch[p][c];
    if(len[p]+1==len[q]) {
        pre[np]=q;
        return ;
    }
    int nq=++cnt;len[nq]=len[p]+1;
    memcpy(ch[nq],ch[q],sizeof(ch[q]));
    pre[nq]=pre[q],pre[q]=pre[np]=nq;
    for(;ch[p][c]==q;p=pre[p])ch[p][c]=nq;
}
void addedge(int u, int v) {
    ++in[v],nxt[++tot]=head[u];head[u]=tot,to[tot]=v;
}
void dfs(int u, int v)
{
    puts(ans);
    for(int i=1;i<=4;++i)
        if(ch[u][i])
        {
            ans[v]=h[i];
            dfs(ch[u][i],v+1);
            ans[v]='\0';
        }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("3446.in","r",stdin);
    freopen("3446.out","w",stdout);
#endif
    cin>>n;
    m['A']=1,m['C']=2,m['G']=3,m['T']=4;
    h[1]='A',h[2]='C',h[3]='G',h[4]='T';
    for(int i=1;i<=n;++i) cin>>s[i];
    for(int i=n;i>=1;--i)
    {
        lst=rt[i]=++cnt;
        for(int j=0;j<s[i].size();++j) extend(rt[i],m[s[i][j]]);
        for(int j=rt[i];j<=cnt;++j)
        {
            for(int k=1;k<=4;++k)
            {
                if(!ch[j][k]) ch[j][k]=get[k];
                if(ch[j][k]) addedge(ch[j][k],j);
            }
        }
        for(int k=1;k<=4;++k)
            if(ch[rt[i]][k]) get[k]=ch[rt[i]][k];
    }
    int k; cin>>k;
    if(k) dfs(rt[1],0);
    int l=1,r=0;
    for(int i=1;i<=cnt;++i)
    {
        pl[i]=1;
        if(!in[i]) q[++r]=i;
    }
    while(l<=r)
    {
        int u=q[l++];
        for(int e=head[u];e;e=nxt[e])
        {
            pl[to[e]]=(pl[to[e]]+pl[u])%Mod;
            --in[to[e]];
            if(!in[to[e]]) q[++r]=to[e];
        }
    }
    cout<<pl[rt[1]];
}

【OJ3446】copy

标签:lin   建立   math   题意   main   pen   turn   字典序   超过   

原文地址:https://www.cnblogs.com/farway17/p/10447669.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!