【GDOI2017 day1】微信

xiaoxiao2021-02-28  94

Description

题意就是,给你n个字符串,然后给你一些二进制,然后求二进制为1的位置他们的最长公共子串。

Solution

这就是一道SAM的裸题。 构出一颗trie,然后trie上建SAM(要用bfs来建),然后每个节点标记一个二进制,最后每个fail树上的父亲把儿子的标记全部or起来。 然后把这个二进制状态更新到子集上,如果 3n 枚举子集会超时,随意要1位位的往下转移 2nn

Code

#include<iostream> #include<stdio.h> #include<math.h> #include<algorithm> #include<string.h> #include<map> #define fo(i,a,b) for(i=a;i<=b;i++) #define fod(i,a,b) for(i=a;i>=b;i--) #define rep(i,a) for(i=first[a];i;i=next[i]) using namespace std; const int maxn=1e6+7; int i,j,k,l,n,m,ans,len,tot,x,op; int num,a[maxn],f[maxn]; int p,np,q,nq,w[maxn*3],er[21],b[maxn*3],c[maxn*3],da,e[maxn*3]; int d[maxn*2]; int tr[maxn*2][26]; char s[maxn],st[maxn]; struct node{ int fa,len,son[26],w; }t[maxn*2]; int extend(int x,int last,int u){ t[np=++num].len=t[p=last].len+1;t[np].w=u; while(p&&!t[p].son[x])t[p].son[x]=np,p=t[p].fa; if(!p)t[np].fa=1; else{ q=t[p].son[x]; if(t[q].len==t[p].len+1)t[np].fa=q; else{ t[nq=++num]=t[q];t[nq].w=u; t[nq].len=t[p].len+1; t[q].fa=t[np].fa=nq; while(p&&t[p].son[x]==q)t[p].son[x]=nq,p=t[p].fa; } } return np; } void bfs(){ int i,j,k,x,y;w[d[1]=0]=1;//w[1]=extend(a[1],d[1]=1); for(i=j=1;i<=j;i++){ x=d[i]; fo(k,0,25){ y=tr[x][k];if(!y)continue; w[d[++j]=y]=extend(k,w[x],b[y]); } } } int main(){ freopen("wechat.in","r",stdin); freopen("wechat.out","w",stdout); er[0]=1;fo(i,1,20)er[i]=er[i-1]*2; scanf("%d",&n);tot=1; fo(i,1,n){ scanf("%s",st+1);len=strlen(st+1);m=0;da=max(da,len);st[++len]='<'; fo(j,1,len)if(st[j]=='<'){ if(st[j-1]!='<'){ x=0; fo(k,1,m){ if(d[k])x=d[k]; else{ if(!tr[x][s[k]-'a'])tr[x][s[k]-'a']=++op; x=tr[x][s[k]-'a'];b[x]|=er[i-1]; } d[k]=x; } } d[m]=0;--m; }else s[++m]=st[j],d[m]=0; fo(j,1,len)d[j]=0; } num=1; bfs(); fo(i,1,num)c[t[i].len]++; fo(i,1,da)c[i]+=c[i-1]; fod(i,num,1)e[c[t[i].len]--]=i; fod(i,num,1)x=e[i],t[t[x].fa].w|=t[x].w; fo(i,1,num)x=e[i],f[t[x].w]=(f[t[x].w]<t[x].len)?t[x].len:f[t[x].w]; fod(i,er[n]-1,1){ fo(j,1,n){ if(i&er[j-1])f[i-er[j-1]]=(f[i-er[j-1]]<f[i])?f[i]:f[i-er[j-1]]; } } for(scanf("%d",&m);m;m--){ scanf("%s",s+1);k=0; fo(i,1,n)if(s[i]=='1')k+=er[i-1]; printf("%d\n",f[k]); } }
转载请注明原文地址: https://www.6miu.com/read-70536.html

最新回复(0)