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

题意

内存限制:1024 MiB
时间限制:5000 ms

现有一个字符串 S S S

Tiffany 将从中划出 n a n_a na 个子串作为 A 类串,第 i i i 个( 1 ≤ i ≤ n a 1\leq i\leq n_a 1ina)为 A i = S ( l a i , r a i ) A_i = S\left( la_i, ra_i\right) Ai=S(lai,rai)

类似地,Yazid 将划出 n b n_b nb 个子串作为 B 类串,第 i i i 个( 1 ≤ i ≤ n b 1\leq i\leq n_b 1inb)为 B i = S ( l b i , r b i ) B_i = S\left( lb_i, rb_i\right) Bi=S(lbi,rbi)

现额外给定 m m m 组支配关系,每组支配关系 ( x , y ) \left( x,y\right) (x,y) 描述了第 x x x 个 A 类串支配 y y y 个 B 类串。

求一个长度最大的目标串 T T T,使得存在一个串 T T T 的分割 T = t 1 + t 2 + ⋯ + t k T=t_1 + t_2 +\dots +t_k T=t1+t2++tk k ≥ 0 k\geq 0 k0)满足:

  • 分割中的每个串 t i t_i ti 均为 A 类串:即存在一个与其相等的 A 类串,不妨假设其为 t i = A i d i t_i = A_{id_i} ti=Aidi
  • 对于分割中所有相邻的串 t i , t i + 1 t_i , t_{i+1} ti,ti+1 1 ≤ i < k 1\leq i < k 1i<k),都有存在一个 A i d i A_{id_i} Aidi 支配的 B 类串,使得该 B 类串为 t i + 1 t_{i+1} ti+1 的前缀。

方便起见,你只需要输出这个最大的长度即可。

特别地,如果存在无限长的目标串(即对于任意一个正整数 n n n,都存在一个满足限制的长度超过 n n n 的串),请输出 − 1 -1 1

1 ≤ ∣ S ∣ ≤ 2 × 1 0 5 1\leq \lvert S\rvert\leq 2\times 10^5 1S2×105 n a , n b ≤ 2 × 1 0 5 n_a , n_b\leq 2\times 10^5 na,nb2×105 m ≤ 2 × 1 0 5 m\leq 2\times 10^5 m2×105

题解

数据千万条,清空第一条。

多测不清空,爆零两行泪。

题意大概就是将A往支配的B连边,B往它作为前缀的A连边的最长路

对于后一部分我们可以反串后建立SAM,建立parent树,然后对于A,B利用倍增找到它所对应的节点

这样可能一个节点对应很多个A和B,所以在每个节点上我们对其按照长度排序,然后B往下一个B连边,A向长度小于等于它的第一个B连反向边,特别的我们可以设立一个特殊点,使其作为B的功能且长度最短

然后对于parent树上的父亲和儿子节点,我们将父亲长度最长的B和儿子的特殊点相连

跑拓扑即可

#include 
using namespace std;
const int N=2e6+5;long long ans,dis[N];
int T,fa[N][20],len[N],lst,sz,n,id[N],na,nb,a[N];
int b[N],cnt,t,hd[N],d[N],V[N],nx[N],h[N],m,ch[N][26];
char s[N];bool isa[N];vectorg[N];queueq;
void add(int u,int v){
	nx[++t]=hd[u];d[V[hd[u]=t]=v]++;
}
int init(int x){
	len[++sz]=x;fa[sz][0]=isa[sz]=0;
	memset(ch[sz],0,sizeof ch[sz]);return sz;
}
void build(int x){
	int p=lst,np=init(len[p]+1);
	while(p && !ch[p][x])
		ch[p][x]=np,p=fa[p][0];
	if (!p) fa[np][0]=1;
	else{
		int q=ch[p][x];
		if (len[q]==len[p]+1) fa[np][0]=q;
		else{
			int nq=init(len[p]+1);
			fa[nq][0]=fa[q][0];
			memcpy(ch[nq],ch[q],sizeof ch[q]);
			fa[q][0]=fa[np][0]=nq;
			while(p && ch[p][x]==q)
				ch[p][x]=nq,p=fa[p][0];
		}
	}
	lst=np;
}
void find(bool ty){
	int x,y;scanf("%d%d",&x,&y);
	y=y-x+1;x=id[x];
	for (int i=18;~i;i--)
		if (len[fa[x][i]]>=y)
			x=fa[x][i];
	isa[++cnt]=ty;len[cnt]=y;
	g[x].push_back(cnt);
}
bool cmp(int A,int B){
	return len[A]>len[B]||(len[A]==len[B]&&isa[A]>isa[B]);
}
int main(){
	for (scanf("%d",&T);T--;ans=0){
		scanf("%s",s+1);n=strlen(s+1);sz=0;lst=init(0);
		for (int i=n;i;i--) build(s[i]-'a'),id[i]=lst;
		for (int j=1;(1<

你可能感兴趣的:(#4350. 「十二省联考 2019」字符串问题)