字符串问题

字符串问题

题目背景
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 }
View Code
原文地址:https://www.cnblogs.com/liankewei/p/10674675.html