十二省联考2019 字符串问题

十二省联考2019 字符串问题


只要有点码力,想明白再写,考场上应该写的出来

首先可以想到,对每个\(A_i\)建一个点,如果\(A_i\)后面可以接\(A_j\),就连一条边\(A_i\rightarrow A_j\),那么设\(A_i\)的点权是\(|A_i|\),跑一个最长链就能解决。

那么根据题意又可以这样连,如果\(A_i\)支配\(B_j\),连一条边\(A_i\rightarrow B_j\);如果\(B_i\)\(A_j\)的前缀,连一条边\(B_i\rightarrow A_j\)

第一种边显然是\(O(n)\)级别的,那么要优化第二种边

显然想到sam,如果\(B\)\(A\)的前缀,那么先把串变成反串,就等价于在sam的parent树上,\(B\)\(A\)的父亲,且\(B.length\leq A.length\)

(这题部分分还是很足的,不考虑\(B.length\leq A.length\)有80分,很nb)

所以可以直接用parent树优化连边,现在只剩下一个问题就是\(B.length\leq A.length\)怎么处理

把sam上每个点建个map,大暴力建一条链,就做完了

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il ll gi(){
    ll x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
char S[200010];
int la[200010],ra[200010],lb[200010],rb[200010];
int a[200010],b[200010];
int fir[2000010],dis[50000010],nxt[50000010],id;
il vd link(int a,int b){
    nxt[++id]=fir[b],fir[b]=id,dis[id]=a;
}
int trans[400010][26],slink[400010],len[400010],cnt,lst,maxl[2000010];
std::map<int,int>map[400010];
il int newnode(){++cnt;memset(trans[cnt],0,sizeof trans[cnt]),slink[cnt]=len[cnt]=0;return cnt;}
il int newnode(int from){++cnt;memcpy(trans[cnt],trans[from],sizeof trans[cnt]),slink[cnt]=slink[from],len[cnt]=len[from];return cnt;}
int leaf[200010];
il vd extend(int x,int i){
    int p=lst,np=newnode();lst=np;leaf[i]=np;len[np]=len[p]+1;
    while(p&&!trans[p][x])trans[p][x]=np,p=slink[p];
    if(!p)slink[np]=1;
    else{
        int q=trans[p][x];
        if(len[q]==len[p]+1)slink[np]=q;
        else{
            int nq=newnode(q);len[nq]=len[p]+1;
            slink[np]=slink[q]=nq;
            while(p&&trans[p][x]==q)trans[p][x]=nq,p=slink[p];
        }
    }
}
int st[19][400010];
ll f[2000010];bool vis[2000010],ansisinf;
bool instk[2000010];
il vd dp(int x){
    if(vis[x])return;
    vis[x]=1;f[x]=0;instk[x]=1;
    for(int i=fir[x];i;i=nxt[i]){
        if(instk[dis[i]]){ansisinf=1;return;}
        if(!vis[dis[i]])dp(dis[i]);
        if(ansisinf)return;
        f[x]=std::max(f[x],f[dis[i]]);
    }
    f[x]+=maxl[x];instk[x]=0;
}
int sec[400010];
int main(){
#ifdef XZZSB
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    int orzyyb=gi(),x,y;
    while(orzyyb--){
        scanf("%s",S+1);
        int n=strlen(S+1);
        std::reverse(S+1,S+n+1);
        cnt=0;lst=newnode();
        for(int i=1;i<=n;++i)extend(S[i]-'a',i);
        int sam=cnt;
        for(int i=2;i<=sam;++i)st[0][i]=slink[i];
        for(int i=1;i<19;++i)for(int j=1;j<=sam;++j)st[i][j]=st[i-1][st[i-1][j]];
        int A=gi();
        for(int i=1;i<=A;++i){
            ra[i]=n-gi()+1,la[i]=n-gi()+1;
            x=leaf[ra[i]];
            for(int j=18;~j;--j)if(len[st[j][x]]>=ra[i]-la[i]+1)x=st[j][x];
            if(map[x].find(ra[i]-la[i]+1)==map[x].end())map[x][ra[i]-la[i]+1]=++cnt;
            a[i]=map[x][ra[i]-la[i]+1];
            link(a[i],++cnt);a[i]=cnt;
            maxl[a[i]]=ra[i]-la[i]+1;
        }
        int B=gi();
        for(int i=1;i<=B;++i){
            rb[i]=n-gi()+1,lb[i]=n-gi()+1;
            x=leaf[rb[i]];
            for(int j=18;~j;--j)if(len[st[j][x]]>=rb[i]-lb[i]+1)x=st[j][x];
            if(map[x].find(rb[i]-lb[i]+1)==map[x].end())map[x][rb[i]-lb[i]+1]=++cnt;
            b[i]=map[x][rb[i]-lb[i]+1];
        }
        for(int i=1;i<=sam;++i){
            int lst=i;
            for(auto j:map[i]){
                if(lst)link(lst,j.second);
                lst=j.second;
            }
            link(lst,sec[i]=++cnt);
        }
        for(int i=2;i<=sam;++i)link(sec[slink[i]],i);
        int m=gi();
        for(int i=1;i<=m;++i)x=gi(),y=gi(),link(a[x],b[y]);
        ansisinf=0;
        ll ans=0;
        for(int i=1;!ansisinf&&i<=cnt;++i)dp(i),ans=std::max(ans,f[i]);
        if(ansisinf)ans=-1;
        printf("%lld\n",ans);
        id=0;memset(fir+1,0,4*cnt);
        for(int i=0;i<19;++i)memset(st[i]+1,0,4*sam);
        memset(vis+1,0,cnt);
        memset(instk+1,0,cnt);
        memset(maxl+1,0,4*cnt);
        for(int i=1;i<=sam;++i)map[i].clear();
        fflush(stdout);
    }
    return 0;
}
posted @ 2019-04-11 22:44  菜狗xzz  阅读(259)  评论(0编辑  收藏  举报