CF1037H Security

FxorG

2021-07-09 08:31:15

Solution

## $\text{Solution}$ 首先对于字典序最小,我们可以来个贪心: 假如是 $aab$ ,那么我们先考虑能不能在 $[L,R]$ 内匹配到 $aab$ ,再考虑能否再添上一个最小的字母。假如不行,返回上一步,找一个大于 $b$ 的最小字母,凑出来就字典序最大了。不行的话就再回跳。 总结下: 1. 假如前面全部一模一样匹配成功,且全部匹配完,只需要看能否添上一个最小的即可。 2. 看能否当前位匹配一样的。 3. 能否匹配更大的,直接退出。 注意下,它们是有优先级的。 那么,对于一个字符串,我们怎么考虑它是否在 $[L,R]$ 出现? 考虑当前匹配到 SAM 的 $p$ 节点,然后 SAM 的父亲是儿子的后缀,说明父亲这个状态在儿子中都有出现过,那么我们只需要判断下这个子树里有没有在 $[L,R]$ 之中的即可。 这里我线段树合并不熟,写了个主席树+dfs序。 ## $\text{Code}$ ```cpp #include <bits/stdc++.h> #define N (int)(3e5+5) using namespace std; struct edge { int nex,to; }e[N]; char s[N]; int head[N],cnt,sz[N],val[N],fa[N],len[N],son[26][N],id[N],rk[N],rt[N],id_tot; int n,m,M,las=1,tot=1; void add_edge(int x,int y) { e[++cnt].nex=head[x]; e[cnt].to=y; head[x]=cnt; } void ins(int c,int v) { int pre=las,x=++tot; las=x; len[x]=len[pre]+1; val[x]=v; for(;pre&&!son[c][pre];pre=fa[pre]) son[c][pre]=x; int y=son[c][pre]; if(!pre) fa[x]=1; else if(len[pre]+1==len[y]) fa[x]=y; else { int p=++tot; len[p]=len[pre]+1; fa[p]=fa[y]; fa[x]=fa[y]=p; for(int i=0;i<26;i++) son[i][p]=son[i][y]; for(;pre&&son[c][pre]==y;pre=fa[pre]) son[c][pre]=p; } //return x; } int dtot=0; void dfs(int x) { id[x]=++dtot; rk[dtot]=x; sz[x]=1; for(int i=head[x];i;i=e[i].nex) { int y=e[i].to; dfs(y); sz[x]+=sz[y]; } } int ls[N*30],rs[N*30],sum[N*30],pos_tot=0; void update(int &cur,int pre,int l,int r,int x) { if(!cur) cur=++pos_tot; sum[cur]=sum[pre]+1; if(l==r) return ; int mid=(l+r)>>1; if(x<=mid) rs[cur]=rs[pre],update(ls[cur],ls[pre],l,mid,x); else ls[cur]=ls[pre],update(rs[cur],rs[pre],mid+1,r,x); } int query(int pre,int cur,int l,int r,int x) { if(l==r&&l==x) return sum[cur]-sum[pre]; if(l==r) return 0; int mid=(l+r)>>1; if(x<=mid) return query(ls[pre],ls[cur],l,mid,x); else return sum[ls[cur]]-sum[ls[pre]]+query(rs[pre],rs[cur],mid+1,r,x); } char ans[N]; int ans_tot=0; bool check(int x,int L,int R) { int l=id[x],r=id[x]+sz[x]-1; // cout<<(char)(x+'a')<<' '<<L<<" "<<R<<" "<<query(rt[l-1],rt[r],1,n,R)-query(rt[l-1],rt[r],1,n,L-1)<<'\n'; return query(rt[l-1],rt[r],1,M,R)-query(rt[l-1],rt[r],1,M,L-1)>0; } bool solve(int p,int x,int l,int r) { if(x==n+1) { for(int i=0;i<26;i++) { if(son[i][p]&&check(son[i][p],l,r)) { ans_tot=x; ans[ans_tot]=i; return 1; } } return 0; } bool fl=0; if(son[s[x]-'a'][p]) { int t=son[s[x]-'a'][p]; if(check(t,l,r)) fl=solve(t,x+1,l+1,r); if(fl) ans[x]=s[x]-'a'; } if(fl) return 1; for(int i=s[x]-'a'+1;i<26;i++) { if(son[i][p]&&check(son[i][p],l,r)) { ans_tot=x; ans[x]=i; return 1; } } return 0; } int main() { scanf("%s%d",s+1,&m); M=n=strlen(s+1); for(int i=1;i<=n;i++) ins(s[i]-'a',i); for(int i=2;i<=tot;i++) add_edge(fa[i],i); dfs(1); //build(1,1,tot); for(int i=1;i<=tot;i++) { if(val[rk[i]]) update(rt[i],rt[i-1],1,n,val[rk[i]]); else rt[i]=rt[i-1]; } for(int i=1;i<=m;i++) { int L,R; scanf("%d%d%s",&L,&R,s+1); n=strlen(s+1); ans_tot=0; if(solve(1,1,L,R)) { for(int i=1;i<=ans_tot;i++) printf("%c",ans[i]+'a'); puts(""); } else puts("-1"); } return 0; } ```