【纪中集训2019.3.19】原样输出

题意

描述:

​ 给出(n)个字符串,你可能会回答两种询问中的一个:

(k=0):其中每个串的连续子串拼接起来共有多少个不同的串;

(k=1):回答(k=0),并且输出所有的子串;

范围:

​ 保证输入不超过(1 M) ,输出不超过(200 M)

题解:

  • 对每个串建后缀自动机;

  • 把每个后缀自动机的空节点仿照子序列自动机那样补上;

  • (dp)统计答案,(dfs)输出方案;

  • 复杂度是(O(4*n))的;

    #include<bits/stdc++.h>
    #define ll long long 
    using namespace std;
    const int N=1<<21,mod=1e9+7; 
    int n,k,nxt[4],l[N];
    int cnt,rt[N],len[N],pa[N],ch[N][4],lst,now,L[N],d[N];
    int st[N],top,c[N],f[N],ans;
    queue<int>q;
    char s[N],mp[4]={'A','C','G','T'};
    int get(char x){return x=='A'?0:x=='C'?1:x=='G'?2:3;}
    void extend(int x){
    	int p=lst,np=++cnt;lst=np;
    	len[np]=len[p]+1;
    	while(p&&!ch[p][x])ch[p][x]=np,p=pa[p];
    	if(!ch[p][x]){pa[np]=now;return;}
    	int q=ch[p][x];
    	if(len[q]==len[p]+1){pa[np]=q;return;}
    	int nq=++cnt;
    	len[nq]=len[p]+1;
    	memcpy(ch[nq],ch[q],sizeof(ch[q]));
    	pa[nq]=pa[q];pa[q]=pa[np]=nq;
    	while(p&&ch[p][x]==q)ch[p][x]=nq,p=pa[p];
    }
    void dfs(int u){
    	for(int i=1;i<=top;++i)putchar(mp[st[i]]);
    	putchar('
    ');ans++;
    	for(int i=0;i<4;++i)if(ch[u][i]){
    		st[++top]=i;
    		dfs(ch[u][i]); 
    		--top;
    	}
    }
    int main(){
    	freopen("copy.in","r",stdin);
    	freopen("copy.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i){
    		scanf("%s",s+1);
    		l[i]=strlen(s+1);
    		rt[i]=now=lst=++cnt;
    		for(int j=1;j<=l[i];++j)extend(get(s[j]));
    	}
    	scanf("%d",&k);
    	for(int i=n;i;--i){
    		now=rt[i];
    		for(int j=now;j<rt[i+1];++j)
    		for(int k=0;k<4;++k)if(!ch[j][k])ch[j][k]=nxt[k];
    		for(int j=0;j<4;++j)if(ch[now][j])nxt[j]=ch[now][j];
    	}
    	if(k==1)dfs(1);
    	else {
    		for(int i=1;i<=cnt;++i)
    		for(int j=0;j<4;++j)d[ch[i][j]]++;
    		for(int i=1;i<=cnt;++i)if(!d[i])q.push(i),st[++top]=i;
    		while(!q.empty()){
    			int x=q.front();q.pop();
    			for(int i=0;i<4;++i)if(!--d[ch[x][i]])q.push(ch[x][i]),st[++top]=ch[x][i];
    		}
    		for(int i=cnt,x;i;--i){
    			f[x=st[i]]++;
    			for(int j=0;j<4;++j)if(ch[x][j]){f[x]+=f[ch[x][j]];if(f[x]>=mod)f[x]-=mod;}
    		}
    		ans=f[1];
    	}
    	printf("%d
    ",ans%mod);
    	return 0;
    }
    
原文地址:https://www.cnblogs.com/Paul-Guderian/p/10560514.html