十二省联考2019 字符串问题
只要有点码力,想明白再写,考场上应该写的出来
首先可以想到,对每个\(A_i\)建一个点,如果\(A_i\)后面可以接\(A_j\),就连一条边\(A_i\rightarrow A_j\),那么设\(A_i\)的点权是\(|A_i|\),跑一个最长链就能解决。
那么根据题意又可以这样连,如果\(A_i\)支配\(B_j\),连一条边\(A_i\rightarrow B_j\);如果\(B_i\)是\(A_j\)的前缀,连一条边\(B_i\rightarrow A_j\)。
第一种边显然是\(O(n)\)级别的,那么要优化第二种边
显然想到sam,如果\(B\)是\(A\)的前缀,那么先把串变成反串,就等价于在sam的parent树上,\(B\)是\(A\)的父亲,且\(B.length\leq A.length\)
(这题部分分还是很足的,不考虑\(B.length\leq A.length\)有80分,很nb)
所以可以直接用parent树优化连边,现在只剩下一个问题就是\(B.length\leq A.length\)怎么处理
把sam上每个点建个map,大暴力建一条链,就做完了
#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il ll gi(){
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
char S[200010];
int la[200010],ra[200010],lb[200010],rb[200010];
int a[200010],b[200010];
int fir[2000010],dis[50000010],nxt[50000010],id;
il vd link(int a,int b){
nxt[++id]=fir[b],fir[b]=id,dis[id]=a;
}
int trans[400010][26],slink[400010],len[400010],cnt,lst,maxl[2000010];
std::map<int,int>map[400010];
il int newnode(){++cnt;memset(trans[cnt],0,sizeof trans[cnt]),slink[cnt]=len[cnt]=0;return cnt;}
il int newnode(int from){++cnt;memcpy(trans[cnt],trans[from],sizeof trans[cnt]),slink[cnt]=slink[from],len[cnt]=len[from];return cnt;}
int leaf[200010];
il vd extend(int x,int i){
int p=lst,np=newnode();lst=np;leaf[i]=np;len[np]=len[p]+1;
while(p&&!trans[p][x])trans[p][x]=np,p=slink[p];
if(!p)slink[np]=1;
else{
int q=trans[p][x];
if(len[q]==len[p]+1)slink[np]=q;
else{
int nq=newnode(q);len[nq]=len[p]+1;
slink[np]=slink[q]=nq;
while(p&&trans[p][x]==q)trans[p][x]=nq,p=slink[p];
}
}
}
int st[19][400010];
ll f[2000010];bool vis[2000010],ansisinf;
bool instk[2000010];
il vd dp(int x){
if(vis[x])return;
vis[x]=1;f[x]=0;instk[x]=1;
for(int i=fir[x];i;i=nxt[i]){
if(instk[dis[i]]){ansisinf=1;return;}
if(!vis[dis[i]])dp(dis[i]);
if(ansisinf)return;
f[x]=std::max(f[x],f[dis[i]]);
}
f[x]+=maxl[x];instk[x]=0;
}
int sec[400010];
int main(){
#ifdef XZZSB
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
int orzyyb=gi(),x,y;
while(orzyyb--){
scanf("%s",S+1);
int n=strlen(S+1);
std::reverse(S+1,S+n+1);
cnt=0;lst=newnode();
for(int i=1;i<=n;++i)extend(S[i]-'a',i);
int sam=cnt;
for(int i=2;i<=sam;++i)st[0][i]=slink[i];
for(int i=1;i<19;++i)for(int j=1;j<=sam;++j)st[i][j]=st[i-1][st[i-1][j]];
int A=gi();
for(int i=1;i<=A;++i){
ra[i]=n-gi()+1,la[i]=n-gi()+1;
x=leaf[ra[i]];
for(int j=18;~j;--j)if(len[st[j][x]]>=ra[i]-la[i]+1)x=st[j][x];
if(map[x].find(ra[i]-la[i]+1)==map[x].end())map[x][ra[i]-la[i]+1]=++cnt;
a[i]=map[x][ra[i]-la[i]+1];
link(a[i],++cnt);a[i]=cnt;
maxl[a[i]]=ra[i]-la[i]+1;
}
int B=gi();
for(int i=1;i<=B;++i){
rb[i]=n-gi()+1,lb[i]=n-gi()+1;
x=leaf[rb[i]];
for(int j=18;~j;--j)if(len[st[j][x]]>=rb[i]-lb[i]+1)x=st[j][x];
if(map[x].find(rb[i]-lb[i]+1)==map[x].end())map[x][rb[i]-lb[i]+1]=++cnt;
b[i]=map[x][rb[i]-lb[i]+1];
}
for(int i=1;i<=sam;++i){
int lst=i;
for(auto j:map[i]){
if(lst)link(lst,j.second);
lst=j.second;
}
link(lst,sec[i]=++cnt);
}
for(int i=2;i<=sam;++i)link(sec[slink[i]],i);
int m=gi();
for(int i=1;i<=m;++i)x=gi(),y=gi(),link(a[x],b[y]);
ansisinf=0;
ll ans=0;
for(int i=1;!ansisinf&&i<=cnt;++i)dp(i),ans=std::max(ans,f[i]);
if(ansisinf)ans=-1;
printf("%lld\n",ans);
id=0;memset(fir+1,0,4*cnt);
for(int i=0;i<19;++i)memset(st[i]+1,0,4*sam);
memset(vis+1,0,cnt);
memset(instk+1,0,cnt);
memset(maxl+1,0,4*cnt);
for(int i=1;i<=sam;++i)map[i].clear();
fflush(stdout);
}
return 0;
}