[十二省联考2019]字符串问题
XIII.[十二省联考2019]字符串问题
首先,我们可以把题目转变成这样:对于一些A类串,其有连向某些B类串的边;对于某些B类串,其又有连向某些A类串的边。要你找出一条权值最长的路径。(此时显然如果成环则答案一定是 )
A到B的串题目已经给出了,关键是B到A的串。
我们发现,若某个 是 的前缀,则 由 在后面添加字符得到,需要在自动姬上搞,我们又不知道什么可以维护自动姬的结构;但是,如果我们把它转成后缀的话,就会发现这时我们变成了在parent tree上搞。处理一棵树可比处理DAG好多了,我们果断尝试这种思路。具体而言,我们翻转整个串,这样要求便变为了 是 的后缀,即 所对应的节点在parent tree上是 的父亲。(当然,实际上我们会发现二者对应的节点可能相同,这时便要判断是否有 ,若成立则 可以到 ;为了统一两组情形,我们在相同节点处就把该节点按照长度不同拆开,这样就还是 节点的所有父亲上的 都连到 )
这样处理完后,我们发现连到 的所有 在 parent tree 上成一条到根的路径。
考虑将图中所有边反向,这时就变成了从最后一个 串到第一个 串的路径。然后,考虑将 parent tree 拷贝一份,一棵代表所有的 串,一棵代表所有的 串。现在,假设这两棵树上初始都没有边,考虑怎样连边让它符合我们的要求。
首先,从最后一个 串出发,要能走到所有路径上的 串;因此,对于 树中每个节点,连到其在 树中对应的节点,并且在 树中让所有的儿子连到父亲,这样便实现了此过程。然后, 还要能回到 ,于是对于一组“支配关系”,直接让它从 上对应节点连到 上对应节点即可。这样搞完后,我们便得到了最终需要的图。
52行极短代码,你值得拥有
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T,n,m,A,B,cnt=1,id[200100],aa[200100],bb[200100],tot,val[1600100],in[1600100];
ll f[1600100],res;
char s[200100];
struct Suffix_Automaton{int ch[26],len,fa;}t[400100];
int Add(int x,int c){
int xx=++cnt;t[xx].len=t[x].len+1;
for(;x&&!t[x].ch[c];x=t[x].fa)t[x].ch[c]=xx;
if(!x){t[xx].fa=1;return xx;}
int y=t[x].ch[c];
if(t[y].len==t[x].len+1){t[xx].fa=y;return xx;}
int yy=++cnt;t[yy]=t[y],t[yy].len=t[x].len+1;
t[xx].fa=t[y].fa=yy;
for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
return xx;
}
int anc[400100][20];
map<int,int>mp[400100];
int substring(int l,int r){//give the substring (l,r) of the original string an identifier
l=n-l,r=n-r,swap(l,r);
int x=id[r];
for(int j=19;j>=0;j--)if(anc[x][j]&&t[anc[x][j]].len>=r-l+1)x=anc[x][j];
if(!mp[x][r-l+1])mp[x][r-l+1]=++tot;
return mp[x][r-l+1];
}
vector<int>v[1600100];
void ae(int x,int y){v[x].push_back(y),in[y]++;}
queue<int>q;
int main(){
scanf("%d",&T);
while(T--){
scanf("%s",s),n=strlen(s),reverse(s,s+n);//reverse the string, making prefix into suffix.
for(int i=0,las=1;i<n;i++)id[i]=las=Add(las,s[i]-'a');
for(int i=1;i<=cnt;i++)mp[i][t[i].len]=++tot,anc[i][0]=t[i].fa;
for(int j=1;j<=19;j++)for(int i=1;i<=cnt;i++)anc[i][j]=anc[anc[i][j-1]][j-1];
scanf("%d",&A);for(int i=1,l,r;i<=A;i++)scanf("%d%d",&l,&r),val[aa[i]=substring(l,r)]=r-l+1;
scanf("%d",&B);for(int i=1,l,r;i<=B;i++)scanf("%d%d",&l,&r),bb[i]=substring(l,r);
for(int i=2;i<=cnt;i++)for(auto it=mp[i].rbegin();it!=mp[i].rend();){
auto ti=it++;
ae(tot+ti->second,tot+(it==mp[i].rend()?mp[t[i].fa].rbegin():it)->second);
}
scanf("%d",&m);for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),ae(bb[y]+tot,aa[x]);
for(int i=1;i<=tot;i++)ae(i,tot+i);for(int i=1;i<=2*tot;i++)if(!in[i])q.push(i);
while(!q.empty()){int x=q.front();q.pop(),f[x]+=val[x];for(auto y:v[x]){f[y]=max(f[y],f[x]);if(!--in[y])q.push(y);}}
for(int i=1;i<=2*tot;i++)if(in[i]){res=-1;break;}else res=max(res,f[i]);printf("%lld\n",res),res=0;
for(int i=1;i<=cnt;i++)memset(t[i].ch,0,sizeof(t[i].ch)),t[i].len=t[i].fa=0,mp[i].clear();cnt=1;
for(int i=1;i<=2*tot;i++)v[i].clear(),val[i]=in[i]=f[i]=0;tot=0;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?