「十二省联考2019」字符串问题

自己搞了一个月的S(wen)A(hua)M(ke),但是好像还是很白给


因为不会 (SA) 所以想想这题目怎么用 (SAM)

预处理显然,倍增跳后缀树维护出来每个点代表的 (a_i or b_i),复杂度 (O((na+nb)log |S|))

如果能连接那么下一个串得是上一个串的限制的前缀

前缀就是反串的后缀

然后建反串的自动机,考虑在这上面得到的 (a o b) 的限制就可以变成 (a)(b) 的子树里面建边了

那么因为是个树,所以有 (dfn) 序,所以线段树优化建图

具体而言就是每个 (a) 点往区间连边,点带权就完事了

写的时候要特别注意 (i or dfn[i])

但是这样的话会发现如果 (a_i) 和某个 (b_j) 倍增到同一个点上了

如果 $a and b $ 共点的时候两个 (len_age len_b) 就是完全可以转移的

那么我原来直接把 (a) 放到 (fa_{id}) 的方法就不奏效了

所以排序然后暴力扫,做前缀优化建图

具体就是按照长度把当前的点的 (a_{len},b_{len}) 排序,把树上的每个点拆成 (num_1)(num_2)

父亲 (num_1) 连给 (b)(b) 连给满足条件的这点的 (a) 或者这个点自己的 (num_2)(a) 只能往外连

然后拓扑即可

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
namespace yspm{
    inline int read(){
        int res=0,f=1; char k;
        while(!isdigit(k=getchar())) if(k=='-') f=-1;
        while(isdigit(k)) res=res*10+k-'0',k=getchar();
        return res*f;
    }    
    const int N=2e5+10,M=N<<1,SZ=M<<3;
    int son[M][26],ed[N],len[M],fa[M],tot=1,las=1;
    int va[N],vb[N],na,nb,slen,id1[N],id2[N],m,num,pre[M],suf[M];
    inline void extend(int x,int id){
        int tmp=las,np=las=++tot; ed[id]=np,len[np]=len[tmp]+1;
        while(tmp&&!son[tmp][x]) son[tmp][x]=np,tmp=fa[tmp];
        if(!tmp) return fa[np]=1,void();
        int q=son[tmp][x]; if(len[q]==len[tmp]+1) return fa[np]=q,void();
        int clone=++tot; fa[clone]=fa[q]; fa[np]=fa[q]=clone; len[clone]=len[tmp]+1; 
        for(reg int i=0;i<26;++i) son[clone][i]=son[q][i];
        while(son[tmp][x]==q) son[tmp][x]=clone,tmp=fa[tmp];
        return ; 
    }
    struct Graph{
        int head[SZ],cnt,f[SZ],in[SZ]; queue<int>q;
        struct node{int to,nxt,dis;}e[SZ<<2];
        inline void add(int u,int v,int w){
            e[++cnt].to=v; e[cnt].nxt=head[u]; e[cnt].dis=w; 
            return head[u]=cnt,void();
        }
        inline int spfa(){
            for(reg int i=1;i<=num;++i){
                for(reg int j=head[i];j;j=e[j].nxt) in[e[j].to]++;
            }
            for(reg int i=1;i<=num;++i) if(!in[i]) q.push(i);
            int ct=0,ans=0;
            while(q.size()){
                int fr=q.front(); q.pop(); ct++; 
                for(reg int i=head[fr];i;i=e[i].nxt){
                    int t=e[i].to; in[t]--; 
                    f[t]=max(f[t],f[fr]+e[i].dis);
                    if(!in[t]) q.push(t);
                }
            } if(ct!=num) return -1;
            for(reg int i=1;i<=num;++i) ans=max(ans,f[i]); return ans;
        }
        inline void clear(){
            for(reg int i=1;i<=cnt;++i) e[i].nxt=e[i].to=e[i].dis=0; 
            for(reg int i=1;i<=num;++i) head[i]=f[i]=in[i]=0; cnt=0;
            return ;
        }
    }G;
    vector<pair<int,int> > g[SZ],h[SZ];
    char s[N];
    int bz[M][20],head[M],cnt; struct node{int to,nxt;}e[M];
    inline void add(int u,int v){return e[++cnt].to=v,e[cnt].nxt=head[u],head[u]=cnt,void();}
    inline void dfs(int x){
        for(reg int i=1;i<=19;++i) bz[x][i]=bz[bz[x][i-1]][i-1];
        for(reg int i=head[x];i;i=e[i].nxt) bz[e[i].to][0]=x,dfs(e[i].to); 
        return ;
    }
    inline int find(int l,int r){
        int now=ed[l]; for(reg int i=19;~i;--i) if(len[bz[now][i]]>=r-l+1) now=bz[now][i];
        return now;
    }
    inline void clear(){
        G.clear(); 
        for(reg int i=1;i<=slen;++i) ed[i]=0; num=0;
        for(reg int i=1;i<=na;++i) va[i]=id1[i]=0; 
        for(reg int i=1;i<=nb;++i) vb[i]=id2[i]=0;
        for(reg int i=1;i<=tot;++i){
            memset(bz[i],0,sizeof(bz[i])); memset(son[i],0,sizeof(son[i]));
            fa[i]=len[i]=head[i]=0; g[i].clear(),h[i].clear();
        } las=tot=1; for(reg int i=1;i<=cnt;++i) e[i].nxt=e[i].to=0; cnt=0;
        
        return ;
    }
    int tp[N];
    inline void work(int i){
        sort(g[i].begin(),g[i].end()); sort(h[i].begin(),h[i].end());
        if(!g[i].size()){
            for(auto p:h[i]) G.add(id2[p.second],suf[i],0);
            return; 
        }
        int now=0,sz=g[i].size(); 
        for(reg int j=0,las=0;j<sz;++j,las=num){
            tp[j]=++num,G.add(num,id1[g[i][j].second],g[i][j].first);
            if(las) G.add(las,num,0);
        } G.add(pre[i],tp[0],0); 
        for(auto p:h[i]){
            while(now<sz&&p.first>g[i][now].first) now++; 
            if(now<sz) G.add(id2[p.second],tp[now],0);
            G.add(id2[p.second],suf[i],0);
        }
        return ;
    }
    signed main(){
        int T=read(); while(T--){ 
            clear(); scanf("%s",s+1); slen=strlen(s+1);
            for(reg int i=slen;i>=1;--i) extend(s[i]-'a',i);
            for(reg int i=2;i<=tot;++i) add(fa[i],i); dfs(1); 
            na=read(); for(reg int i=1,tl,tr;i<=na;++i) tl=read(),tr=read(),va[i]=tr-tl+1,g[id1[i]=find(tl,tr)].push_back(make_pair(va[i],i));
            nb=read(); for(reg int i=1,tl,tr;i<=nb;++i) tl=read(),tr=read(),vb[i]=tr-tl+1,h[id2[i]=find(tl,tr)].push_back(make_pair(vb[i],i));

            for(reg int i=1;i<=na;++i) id1[i]=++num; for(reg int i=1;i<=nb;++i) id2[i]=++num;
            m=read(); for(reg int i=1,ai,bi;i<=m;++i) ai=read(),bi=read(),G.add(id1[ai],id2[bi],0);
            pre[1]=++num; suf[1]=++num; G.add(pre[1],suf[1],0); for(reg int i=2;i<=tot;++i) pre[i]=++num,suf[i]=++num;
            for(reg int i=2;i<=tot;++i) G.add(suf[fa[i]],pre[i],0),G.add(pre[i],suf[i],0);
            
            for(reg int i=1;i<=tot;++i) work(i); 
            printf("%lld
",G.spfa());
            //exit(0);
        }
        return 0;
    }
}
signed main(){return yspm::main();}
原文地址:https://www.cnblogs.com/yspm/p/14213569.html