字符串问题
题目背景
Yazid 和 Tiffany 喜欢字符串问题。在这里,我们将给你介绍一些关于字符串的基本概念。
对于一个字符串 $S$, 我们定义 $lvert S vert$ 表示 $S$ 的长度。
接着,我们定义该串的子串 $Sleft( {L,R} ight)$ 表示由 $S$ 中从左往右数,第 $L$ 个字符到第 $R$ 个字符依次连接形成的字符串,特别地,如果 $L < 1$ 或 $R > lvert S vert$ 或 $L > R$,则 $Sleft( {L,R} ight)$ 表示空串。
我们说两个字符串相等,当且仅当它们的长度相等,且从左至右各位上的字符依次相同。
我们说一个字符串 $T$ 是 $S$ 的**前缀**,当且仅当 $Sleft( 1,lvert T vert ight)=T$。
两个字符串 $S,T$ 相加 $S+T$ 表示的是在 $S$ 后紧挨着写下 $T$ 得到的长度为 $lvert S vert+lvert T vert$ 的字符串。
题目描述
现有一个字符串 $S$。
Tiffany 将从中划出 $n_a$ 个子串作为 A 类串,第 $i$ 个($1leq ileq n_a$)为 $A_i = Sleft( la_i, ra_i ight)$。
类似地,Yazid 将划出 $n_b$ 个子串作为 B 类串,第 $i$ 个($1leq ileq n_b$)为 $B_i = Sleft( lb_i, rb_i ight)$。
现额外给定 $m$ 组支配关系,每组支配关系 $left( x,y ight)$ 描述了第 $x$ 个 A 类串**支配**第 $y$ 个 B 类串。
求一个**长度最大**的目标串 $T$,使得存在一个串 $T$ 的分割 $T=t_1 + t_2 +dots +t_k$($kgeq 0$)满足:
- 分割中的每个串 $t_i$ 均为 A 类串:即存在一个与其相等的 A 类串,不妨假设其为 $t_i = A_{id_i}$。
- 对于分割中所有相邻的串 $t_i , t_{i+1}$($1leq i < k$),都有存在一个 $A_{id_i}$ 支配的 B 类串,使得该 B 类串为 $t_{i+1}$ 的前缀。
方便起见,你只需要输出这个最大的长度即可。
特别地,如果存在无限长的目标串(即对于任意一个正整数 $n$,都存在一个满足限制的长度超过 $n$ 的串),请输出 $-1$。
solution
首先考虑暴力建图:A向支配的B连,B向前缀包含它的连。然后跑拓扑序dp。 40‘(我这咋只有20)
用sam优化:用反串建,则x为x的后代的前缀。
那么可以把par树连起来,然后支配边照常连,边数2n 。80’
不能满分是因为如果b[i]>a[i],连边后可能两个B被压在了同一个节点,但是一个可以被支配,一个不行。
把一个sam节点上的所有串按长度排序,从长度小的开始连,每次当前点与它的上一个b点。相当于串了起来。
这样子如果A能支配某一个B1,那么他只会连到这个B1,然后再间接的连到一个比B1长的B2...
而如果B2是某个串的前缀,那么B1也是。
于是就好了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<vector> 8 #include<queue> 9 #define maxn 800005 10 using namespace std; 11 int T,na,nb,m,cnt,rt,la,al; 12 int head[maxn],tot,pl[maxn],f[maxn][22],out[maxn],top[maxn]; 13 long long dp[maxn];char ch[maxn]; 14 vector<int>G[maxn],p[maxn]; 15 struct node{int v,nex;}e[maxn*2]; 16 struct no{ 17 int par,nex[26],Max,ed; 18 }s[maxn]; 19 struct Node{ 20 int l,r,len; 21 }a[maxn],b[maxn]; 22 void Q(){ 23 for(int i=0;i<=cnt+na+nb;i++){ 24 head[i]=pl[i]=0; 25 out[i]=0;G[i].clear();p[i].clear(); 26 dp[i]=top[i]=0; 27 } 28 cnt=rt=la=1;tot=0; 29 memset(f,0,sizeof f); 30 memset(s,0,sizeof s); 31 } 32 void ins(int c,int id){ 33 int np=++cnt,p=la;la=np; 34 s[np].ed=id;s[np].Max=s[p].Max+1;pl[id]=cnt; 35 for(;p&&!s[p].nex[c];p=s[p].par)s[p].nex[c]=np; 36 if(!p)s[np].par=rt; 37 else { 38 int q=s[p].nex[c]; 39 if(s[q].Max==s[p].Max+1)s[np].par=q; 40 else { 41 int nq=++cnt; 42 s[nq].Max=s[p].Max+1;s[nq].par=s[q].par; 43 for(int i=0;i<26;i++)s[nq].nex[i]=s[q].nex[i]; 44 s[q].par=s[np].par=nq; 45 for(;s[p].nex[c]==q;p=s[p].par)s[p].nex[c]=nq; 46 } 47 } 48 } 49 void dfs(int k,int fa){ 50 f[k][0]=fa; 51 for(int i=0;i<G[k].size();i++)dfs(G[k][i],k); 52 } 53 bool cmp(int A,int B){ 54 int xa=A,xb=B; 55 if(A>cnt+na)A=b[A-cnt-na].len; 56 else A=a[A-cnt].len; 57 if(B>cnt+na)B=b[B-cnt-na].len; 58 else B=a[B-cnt].len; 59 return A<B||A==B&&xa>xb; 60 } 61 void add(int t1,int t2){ 62 e[++tot].v=t1;e[tot].nex=head[t2];head[t2]=tot; 63 out[t1]++; 64 } 65 void init(){ 66 scanf("%s",ch+1);int len=strlen(ch+1); 67 for(int i=len;i>=1;i--){ 68 ins(ch[i]-'a',i); 69 } 70 scanf("%d",&na);for(int i=1;i<=na;i++)scanf("%d%d",&a[i].l,&a[i].r),a[i].len=a[i].r-a[i].l+1; 71 scanf("%d",&nb);for(int i=1;i<=nb;i++)scanf("%d%d",&b[i].l,&b[i].r),b[i].len=b[i].r-b[i].l+1; 72 for(int i=1;i<=cnt;i++)G[s[i].par].push_back(i); 73 dfs(rt,0); 74 for(int j=1;j<=20;j++) 75 for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1]; 76 for(int i=1;i<=na;i++){ 77 int t=pl[a[i].l],L=a[i].len; 78 for(int j=20;j>=0;j--){ 79 int v=f[t][j];if(s[v].Max>=L)t=v; 80 } 81 p[t].push_back(cnt+i); 82 } 83 for(int i=1;i<=nb;i++){ 84 int t=pl[b[i].l],L=b[i].len; 85 for(int j=20;j>=0;j--){ 86 int v=f[t][j];if(s[v].Max>=L)t=v; 87 } 88 p[t].push_back(cnt+na+i); 89 } 90 for(int i=1;i<=cnt;i++)sort(p[i].begin(),p[i].end(),cmp); 91 92 for(int i=1;i<=cnt;i++){ 93 int lb=i; 94 for(int j=0;j<p[i].size();j++){ 95 int t=p[i][j]; 96 if(t>cnt+na)add(lb,t),lb=t; 97 else add(lb,t); 98 } 99 top[i]=lb; 100 } 101 for(int i=1;i<=cnt;i++) 102 if(s[i].par){ 103 add(top[s[i].par],i); 104 } 105 cin>>m; 106 for(int i=1,t1,t2;i<=m;i++){ 107 scanf("%d%d",&t1,&t2); 108 add(cnt+t1,cnt+na+t2); 109 } 110 al=cnt+na+nb; 111 } 112 void tp(){ 113 queue<int>q; 114 for(int i=1;i<=al;i++)if(!out[i])q.push(i); 115 while(!q.empty()){ 116 int x=q.front();q.pop(); 117 if(x>cnt&&x<=cnt+na)dp[x]+=a[x-cnt].len; 118 for(int i=head[x];i;i=e[i].nex){ 119 dp[e[i].v]=max(dp[e[i].v],dp[x]); 120 if(!(--out[e[i].v]))q.push(e[i].v); 121 } 122 } 123 for(int i=1;i<=al;i++)if(out[i]>0){puts("-1");return;} 124 long long ans=0; 125 for(int i=1;i<=al;i++)ans=max(ans,dp[i]); 126 cout<<ans<<endl; 127 } 128 int main(){ 129 cin>>T; 130 while(T--){ 131 Q(); 132 init(); 133 tp(); 134 } 135 return 0; 136 }