字符串问题

字符串问题

题目背景
Yazid 和 Tiffany 喜欢字符串问题。在这里,我们将给你介绍一些关于字符串的基本概念。

对于一个字符串 S, 我们定义 |S| 表示 S 的长度。

接着,我们定义该串的子串 S(L,R) 表示由 S 中从左往右数,第 L 个字符到第 R 个字符依次连接形成的字符串,特别地,如果 L<1R>|S|L>R,则 S(L,R) 表示空串。

我们说两个字符串相等,当且仅当它们的长度相等,且从左至右各位上的字符依次相同。

我们说一个字符串 TS 的**前缀**,当且仅当 S(1,|T|)=T

两个字符串 S,T 相加 S+T 表示的是在 S 后紧挨着写下 T 得到的长度为 |S|+|T| 的字符串。

题目描述
现有一个字符串 S

Tiffany 将从中划出 na 个子串作为 A 类串,第 i 个(1ina)为 Ai=S(lai,rai)

类似地,Yazid 将划出 nb 个子串作为 B 类串,第 i 个(1inb)为 Bi=S(lbi,rbi)

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

求一个**长度最大**的目标串 T,使得存在一个串 T 的分割 T=t1+t2++tkk0)满足:

- 分割中的每个串 ti 均为 A 类串:即存在一个与其相等的 A 类串,不妨假设其为 ti=Aidi
- 对于分割中所有相邻的串 ti,ti+11i<k),都有存在一个 Aidi 支配的 B 类串,使得该 B 类串为 ti+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
复制代码

 

posted @   liankewei123456  阅读(384)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示