• [十二省联考2019]字符串问题


    传送门

    Description

    现有一个字符串 (S)

    从中划出 (n_a)个子串作为 (A) 类串,第 (i)个((1 leqslant i leqslant n_a))为 (A_i = S(la_i, ra_i))

    类似地,划出 (n_b)个子串作为 (B) 类串,第 (i)个((1 leqslant i leqslant n_b))为 (B_i = S(lb_i, rb_i))

    给定 (m) 组支配关系,每组支配关系 ((x, y)) 描述了第 (x)(A)类串支配. 第 (y)(B) 类串。

    求一个长度最大的目标串 (T = t_1+t_2+· · ·+t_k)(k⩾0))满足:

    • 分割中的每个串 (t_i) 均为(A)类串
    • 对于分割中所有相邻的串 (t_i), (t_{i+1})(1 leqslant i < k)),都有存在一个(t_i)支配的 (B) 类串,使得该 (B) 类串为 (t_{i+1})的前缀。

    输出这个最大的长度。如果存在无穷大的长度,则输出(-1)

    Description

    题意就是:我们要找到每个(A)类串是否能作为另一个串的后继,连边,跑最长路,如果有环就输出(-1)

    重点在于如何优化连边:

    1. 线段树优化连边?其实是可以的
    2. 前后缀优化连边?想太多
    3. *后缀树优化连边?就它啦

    我们的连边方式其实上是,(A)类串向其能够支配的(B)类串连边,然后(B)类串再向能作为其前缀的(A)类串连边,显然,我们在(B ightarrow A)上进行优化

    优化(1):考虑到较小的(B)类串可以向较大的(B)类串连边,就可省去部分(B ightarrow A)的边

    把前缀换成后缀,也就是处理原串的反串,建出它的后缀自动机

    然后我们就能得到一棵(parent)树,这棵树上每个节点所带表的串是其子树内其它串的后缀

    那么也就是原串中的前缀

    首先,我们对于每个(A)(B)类串,找到它在后缀自动机上的位置,显然有可能有多个串位于同一个位置

    怎么找位置呢,倍增就行啦

    优化(2):对于(parent)树上的父节点,向其子节点连边

    但是有可能有多个串处在同一个节点上,把点按照大小排序,相同长度的(A)类串位于(B)类串之后,然后每个(B)串只向长度大于等于它的且小于下一个(B)串的(A)类串连边,只需最后一个(B)类串向子节点的第一个(B)串连边即可。


    Code 

    
    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)>(b)?(b):(a))
    #define reg register
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MN=2e5+5;
    char s[MN];
    int na,nb;
    struct Str{int l,r;}a[MN<<1];
    
    int last,cnt,len,step[MN<<1],c[MN<<1][27],fail[MN<<1][22],pos[MN];
    
    
    struct edge{int to,nex;}sam[MN<<1],e[MN<<4];
    int shr[MN<<1],hr[MN<<1],sen,en,rdu[MN<<1];
    void ins(int x,int y,int *h,int &_,edge *E){E[++_]=(edge){y,h[x]};h[x]=_;}
    void Ins(int x,int y){ins(x,y,hr,en,e);++rdu[y];}
    
    void Insert(int x)
    {
    	int p=last,np=++cnt;step[np]=step[p]+1;
    	pos[len-step[np]+1]=np;
    	for(;p&&!c[p][x];p=fail[p][0]) c[p][x]=np;
    	if(!p) fail[np][0]=1;
    	else
    	{
    		int q=c[p][x];
    		if(step[q]==step[p]+1) fail[np][0]=q;
    		else
    		{
    			int nq=++cnt;step[nq]=step[p]+1;
    			memcpy(c[nq],c[q],sizeof c[q]);
    			fail[nq][0]=fail[q][0];fail[q][0]=fail[np][0]=nq;
    			for(;c[p][x]==q;p=fail[p][0])c[p][x]=nq;
    		}
    	}
    	last=np;
    }
    
    int get(int x,int Len)
    {
    	reg int i,o=pos[x];
    	for(i=20;~i;--i)if(step[fail[o][i]]>=Len) o=fail[o][i];
    	return o;
    }
    
    std::vector<int> Set[MN<<1];
    
    void dfs(int x,int fa,int las)
    {
    	reg int i;
    	for(i=0;i<Set[x].size();++i)
    		if(Set[x][i]<=na) {if(~las) Ins(las,Set[x][i]);}
    		else {if(~las) Ins(las,Set[x][i]);las=Set[x][i];}
    	for(i=shr[x];i;i=sam[i].nex)if(sam[i].to!=fa)
    		dfs(sam[i].to,x,las);
    }
    
    #define ln(x) (a[x].r-a[x].l+1)
    bool cmp(int i,int j){return ln(i)<ln(j)||(ln(i)==ln(j)&&i>j);}
    void pre_work()
    {
    	reg int i,j;
    	for(i=1;i<=cnt;++i) Set[i].clear();
    	
    	for(i=2;i<=cnt;++i)
    		ins(fail[i][0],i,shr,sen,sam);
    	
    	for(i=1;i<=20;++i)
    	for(j=1;j<=cnt;++j)
    		fail[j][i]=fail[fail[j][i-1]][i-1];
    	
    	for(i=1;i<=na+nb;++i)
    		Set[get(a[i].l,ln(i))].push_back(i);
    	
    	for(i=1;i<=cnt;++i)
    		std::sort(Set[i].begin(),Set[i].end(),cmp);
    		
    	dfs(1,0,-1);
    }
    
    int visnum;
    ll f[MN<<2];
    std::queue<int> q;
    void topo()
    {
    	reg int i;visnum=0;
    	memset(f,0,sizeof f);
    	
    	for(i=1;i<=na+nb;++i)
    		if(!rdu[i]) q.push(i);
    	
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		if(u<=na) ++visnum,f[u]+=ln(u);
    		for(i=hr[u];i;i=e[i].nex)
    		{
    			f[e[i].to]=max(f[e[i].to],f[u]);
    			if(!--rdu[e[i].to]) q.push(e[i].to);
    		}
    	}
    }
    
    void init()
    {
    	memset(fail,0,sizeof fail);
    	last=1;cnt=1;sen=en=0;
    	memset(rdu,0,sizeof rdu);
    	memset(shr,0,sizeof shr);
    	memset(hr,0,sizeof hr);
    	memset(c,0,sizeof c);
    }
    
    int main()
    {
    	reg int T=read(),i,x;
    	while(T--)
    	{
    		init();
    		
    		scanf("%s",s+1);len=strlen(s+1);
    		for(i=len;i;--i) Insert(s[i]-'a');
    		
    		na=read();
    		for(i=1;i<=na;++i) a[i].l=read(),a[i].r=read();
    		nb=read();
    		for(i=1+na;i<=na+nb;++i) a[i].l=read(),a[i].r=read();
    		
    		pre_work();
    		
    		i=read();
    		while(i--) x=read(),Ins(x,read()+na);
    		
    		topo();
    		
    		if(visnum<na) puts("-1");
    		else
    		{
    			reg ll ans=0;
    			for(i=1;i<=na;++i) ans=max(ans,f[i]);
    			printf("%lld
    ",ans);
    		}
    	}
    	return 0;
    }
    
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    HDU
    HDU
    HDU
    【JZOJ4231】寻找神格【分块】
    【JZOJ4231】寻找神格【分块】
    【JZOJ4230】淬炼神体【数论,数学】【二分】
    【JZOJ4230】淬炼神体【数论,数学】【二分】
    【JZOJ4229】学习神技【数论,数学】
    【JZOJ4229】学习神技【数论,数学】
    【JZOJ3771】【NOI2015模拟8.15】小 Z 的烦恼【高精度】【数论】
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10689702.html
Copyright © 2020-2023  润新知