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

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

当场就去世了,我这菜人改了一下午


考虑一个A,B之间的连边实际表示了两个A之间的有向边,然后把A的连边处理好,就转成了拓扑排序找环+最长链

但是边数很多,考虑优化连边

A,B之间的连边显然没法优化的,考虑一个B可以表示所有它的后缀A

把串反向建出SAM,然后一个B的后缀就是par树的子树

可以拿倍增定位

好了这题就没了

注意到一个事情,定位的点可能重复,于是对SAM拆点,每个点挂一个vector表示一个A或者B的点在SAM的这个位置

然后考虑如何连边

一个B所可以代表的A的集合就是B所在位置的vector中长度不小于Ta的A以及par子树中的A

可以对每个点的vector排序,然后每个B连后面的A,直到下一个B出现或者末尾。

每个末尾的B像par树儿子的开头连边

然后A,B之间的连边照连

之后跑topo就可以了

复杂度\(O(n\log n)\),瓶颈在倍增和清空SAM


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <algorithm>
#define ll long long
const int N=8e5+10;
template <class T>
void read(T &x)
{
    x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int head[N],to[N<<1],Next[N<<1],in[N],cnt;
void add(int u,int v)
{
    ++in[v],to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int ch[N][26],len[N],par[N],tot=1,las=1;
void extend(int c)
{
    int now=++tot,p=las;
    len[now]=len[p]+1;
    while(p&&!ch[p][c]) ch[p][c]=now,p=par[p];
    if(!p) par[now]=1;
    else
    {
        int x=ch[p][c];
        if(len[x]==len[p]+1) par[now]=x;
        else
        {
            int y=++tot;
            par[y]=par[x];
            len[y]=len[p]+1;
            memcpy(ch[y],ch[x],sizeof ch[y]);
            while(p&&ch[p][c]==x) ch[p][c]=y,p=par[p];
            par[now]=par[x]=y;
        }
    }
    las=now;
}
int f[20][N];
int Find(int x,int l)
{
    for(int i=19;~i;i--)
        if(len[f[i][x]]>=l)
            x=f[i][x];
    return x;
}
int na,nb,m;
int val[N],posa[N],posb[N];
ll dp[N];
int is[N],tot2,Las[N];
std::vector<int> yuy[N];
void Clear()
{
    for(int i=1;i<=tot2;i++)
    {
        for(int j=0;f[j][i];j++)
            f[j][i]=0;
        in[i]=dp[i]=val[i]=0;
        memset(ch[i],0,sizeof ch[i]);
        par[i]=len[i]=0;
        Las[i]=0;
        head[i]=0;
        is[i]=0;
        yuy[i].clear();
    }
    for(int i=1;i<=na;i++) posa[i]=0;
    for(int i=1;i<=nb;i++) posb[i]=0;
    tot=las=1;
    tot2=cnt=0;
}
char s[N];
int pos[N],tax[N],A[N],q[N];
bool cmp(int a,int b){return val[a]==val[b]?is[a]<is[b]:val[a]<val[b];}
void work()
{
    scanf("%s",s+1);
    int n=strlen(s+1);
    for(int i=n;i;i--) extend(s[i]-'a'),pos[n+1-i]=las;
    for(int i=0;i<=n;i++) tax[i]=0;
    for(int i=1;i<=tot;i++) ++tax[len[i]];
    for(int i=1;i<=n;i++) tax[i]+=tax[i-1];
    for(int i=1;i<=tot;i++) A[tax[len[i]]--]=i;
    for(int i=1;i<=tot;i++)
    {
        int now=A[i];
        f[0][now]=par[now];
        for(int j=1;f[j-1][now];j++)
            f[j][now]=f[j-1][f[j-1][now]];
    }
    read(na);
    tot2=tot;
    for(int l,r,p,i=1;i<=na;i++)
    {
        read(l),read(r);
        l=n+1-l,r=n+1-r;
        p=Find(pos[l],l+1-r);
        yuy[p].push_back(posa[i]=++tot2);
        val[tot2]=l+1-r;
        is[tot2]=1;
    }
    read(nb);
    for(int l,r,p,i=1;i<=nb;i++)
    {
        read(l),read(r);
        l=n+1-l,r=n+1-r;
        p=Find(pos[l],l+1-r);
        yuy[p].push_back(posb[i]=++tot2);
        val[tot2]=l+1-r;
    }
    for(int i=1;i<=tot;i++)
    {
        std::sort(yuy[i].begin(),yuy[i].end(),cmp);
        int las=i;
        for(int j=0;j<yuy[i].size();j++)
        {
            int now=yuy[i][j];
            add(las,now);
            if(!is[now]) val[now]=0,las=now;
        }
        Las[i]=las;
    }
    for(int i=2;i<=tot;i++)
        add(Las[par[i]],i);
    read(m);
    for(int u,v,i=1;i<=m;i++)
    {
        read(u),read(v);
        u=posa[u],v=posb[v];
        add(u,v);
    }
    int l=1,r=0;
    ll mx=0;
    for(int i=1;i<=tot2;i++)
        if(!in[i])
            q[++r]=i,mx=mx>val[i]?mx:val[i],dp[i]=val[i];
    while(l<=r)
    {
        int now=q[l++];
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i];
            --in[v];
            dp[v]=std::max(dp[v],dp[now]+val[v]);
            mx=mx>dp[v]?mx:dp[v];
            if(!in[v]) q[++r]=v;
        }
    }
    for(int i=1;i<=tot2;i++)
        if(in[i])
        {
            puts("-1");
            Clear();
            return;
        }
    printf("%lld\n",mx);
    Clear();
}
int main()
{
    int T;read(T);
    while(T--) work();
    return 0;
}

2019.4.9

猜你喜欢

转载自www.cnblogs.com/butterflydew/p/10678492.html
今日推荐