CF1037H. Security
Solution 1
设原串为 s t st st。
对于单个询问,答案必然是询问串 s s s的一个前缀 s [ 1.. i ] s[1..i] s[1..i]加上一个大于 s [ i + 1 ] s[i+1] s[i+1]的字符 c c c构成。
因此我们只需要枚举前缀 s [ 1.. i ] s[1..i] s[1..i],枚举字符 c c c,快速询问 s [ 1.. i ] + c s[1..i]+c s[1..i]+c有没有在 s t [ l , r ] st[l,r] st[l,r]中出现过,后缀自动机+线段树合并,记录区间内存在的末尾位置个数即可。
时间复杂度 O ( 26 ∗ n l g n ) O(26*nlgn) O(26∗nlgn)
Solution 2
我们发现我们用线段树合并记录区间末尾位置个数并不优,我们考虑直接记录区间内是否有 c c c的可行转移,因为字符集只有 26 26 26,我们可以把它压成 2 26 2^{26} 226的 i n t int int,即可快速判断是否可以转移。
时间复杂度 O ( ( 26 + l g n ) ∗ n ) O((26+lgn)*n) O((26+lgn)∗n)
Code 1
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
using namespace std;
template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;
const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=1e9+7;
const int MAXN=400005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
int f=1,x=0; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
return x*f;
}
char St[MAXN],st[MAXN];
int ls[MAXN*20],rs[MAXN*20],s[MAXN*20],rt[MAXN],nw[MAXN],nodenum=0;
void print(int x,int y)
{
for (int i=1;i<=x;i++) putchar(St[i]);
putchar(y+'a');
puts("");
}
int query(int x,int l,int r,int L,int R)
{
if (L>R||!x) return 0;
if (l>=L&&r<=R) return s[x];
int mid=(l+r)>>1;
if (R<=mid) return query(ls[x],l,mid,L,R);
else if (L>mid) return query(rs[x],mid+1,r,L,R);
else return query(ls[x],l,mid,L,mid)+query(rs[x],mid+1,r,mid+1,R);
}
int merge(int x,int y)
{
if (!x||!y) return x|y;
int z=++nodenum;
s[z]=s[x]+s[y];
ls[z]=merge(ls[x],ls[y]);
rs[z]=merge(rs[x],rs[y]);
return z;
}
int update(int x,int l,int r,int y)
{
if (!x) x=++nodenum;
s[x]++;
if (l==r) return x;
int mid=(l+r)>>1;
if (y<=mid) ls[x]=update(ls[x],l,mid,y);
else rs[x]=update(rs[x],mid+1,r,y);
return x;
}
int t[MAXN][26],len[MAXN],fa[MAXN],Lst[MAXN],sz=2,lst=1;
void insert(int c,int id)
{
int p=lst,np=lst=sz++;
len[np]=len[p]+1,Lst[id]=np;
for (;p&&!t[p][c];p=fa[p]) t[p][c]=np;
if (!p) { fa[np]=1; return; }
int q=t[p][c];
if (len[q]==len[p]+1) fa[np]=q;
else
{
int nq=sz++;
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
len[nq]=len[p]+1;
memcpy(t[nq],t[q],sizeof t[0]);
for (;t[p][c]==q;p=fa[p]) t[p][c]=nq;
}
}
int c[MAXN]={1},a[MAXN];
void Init()
{
for (int i=1;i<sz;i++) c[i]=0;
for (int i=1;i<sz;i++) c[len[i]]++;
for (int i=1;i<sz;i++) c[i]+=c[i-1];
for (int i=sz-1;i>=1;i--) a[--c[len[i]]]=i;
for (int i=sz-1;i>=1;i--) rt[fa[a[i]]]=merge(rt[fa[a[i]]],rt[a[i]]);
}
signed main()
{
scanf("%s",st+1);
int len=strlen(st+1);
for (int i=1;i<=len;i++) insert(st[i]-'a',i);
for (int i=1;i<=len;i++) rt[Lst[i]]=update(rt[Lst[i]],1,sz,i);
Init();
int Case=read();
while (Case--)
{
int l=read(),r=read();
scanf("%s",St+1);
int Len=strlen(St+1),id=Len+1;
nw[0]=1;
for (int i=1;i<=Len;i++)
{
if (t[nw[i-1]][St[i]-'a']&&query(rt[t[nw[i-1]][St[i]-'a']],1,sz,l+i-1,r)) nw[i]=t[nw[i-1]][St[i]-'a'];
else { id=i; break; }
}
int flag=0;
for (int i=id;i>=1;i--)
{
for (int j=(i>Len?0:St[i]-'a'+1);j<26;j++)
if (t[nw[i-1]][j]&&query(rt[t[nw[i-1]][j]],1,sz,l+i-1,r)) { print(i-1,j),flag=1; break; }
if (flag) break;
}
if (!flag) puts("-1");
}
return 0;
}
Code 2
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
using namespace std;
template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;
const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=1e9+7;
const int MAXN=400005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
int f=1,x=0; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
return x*f;
}
char St[MAXN],st[MAXN];
int ls[MAXN*20],rs[MAXN*20],s[MAXN*20],rt[MAXN],nw[MAXN],Q[MAXN],nodenum=0;
void print(int x,int y)
{
for (int i=1;i<=x;i++) putchar(St[i]);
int t=0;
while (!(y&1)) y>>=1,t++;
putchar(t+'a');
puts("");
}
int query(int x,int l,int r,int L,int R)
{
if (L>R||!x) return 0;
if (l>=L&&r<=R) return s[x];
int mid=(l+r)>>1;
if (R<=mid) return query(ls[x],l,mid,L,R);
else if (L>mid) return query(rs[x],mid+1,r,L,R);
else return query(ls[x],l,mid,L,mid)|query(rs[x],mid+1,r,mid+1,R);
}
int merge(int x,int y)
{
if (!x||!y) return x|y;
int z=++nodenum;
s[z]=s[x]|s[y];
ls[z]=merge(ls[x],ls[y]);
rs[z]=merge(rs[x],rs[y]);
return z;
}
int update(int x,int l,int r,int y,int z)
{
if (!x) x=++nodenum;
s[x]|=z;
if (l==r) return x;
int mid=(l+r)>>1;
if (y<=mid) ls[x]=update(ls[x],l,mid,y,z);
else rs[x]=update(rs[x],mid+1,r,y,z);
return x;
}
int t[MAXN][26],len[MAXN],fa[MAXN],Lst[MAXN],sz=2,lst=1;
void insert(int c,int id)
{
int p=lst,np=lst=sz++;
len[np]=len[p]+1,Lst[id]=np;
for (;p&&!t[p][c];p=fa[p]) t[p][c]=np;
if (!p) { fa[np]=1; return; }
int q=t[p][c];
if (len[q]==len[p]+1) fa[np]=q;
else
{
int nq=sz++;
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
len[nq]=len[p]+1;
memcpy(t[nq],t[q],sizeof t[0]);
for (;t[p][c]==q;p=fa[p]) t[p][c]=nq;
}
}
int c[MAXN]={1},a[MAXN];
void Init()
{
for (int i=1;i<sz;i++) c[i]=0;
for (int i=1;i<sz;i++) c[len[i]]++;
for (int i=1;i<sz;i++) c[i]+=c[i-1];
for (int i=sz-1;i>=1;i--) a[--c[len[i]]]=i;
for (int i=sz-1;i>=1;i--) rt[fa[a[i]]]=merge(rt[fa[a[i]]],rt[a[i]]);
}
signed main()
{
scanf("%s",st+1);
int len=strlen(st+1); Lst[0]=1;
for (int i=1;i<=len;i++) insert(st[i]-'a',i);
for (int i=1;i<=len;i++) rt[Lst[i-1]]=update(rt[Lst[i-1]],0,sz,i-1,1<<(st[i]-'a'));
Init();
int Case=read();
while (Case--)
{
int l=read(),r=read();
scanf("%s",St+1);
int Len=strlen(St+1),id=Len;
nw[0]=1;
for (int i=1;i<=Len;i++)
{
if (((Q[i-1]=query(rt[nw[i-1]],0,sz,l+i-2,r-1))>>(St[i]-'a'))&1) nw[i]=t[nw[i-1]][St[i]-'a'];
else { id=i-1; break; }
}
Q[Len]=query(rt[nw[Len]],0,sz,l+Len-1,r-1);
int flag=0;
for (int i=id;i>=0;i--)
{
int p=Q[i],q=(i>=Len?0:St[i+1]-'a'+1);
if (p>=(1<<q)) { p^=p&((1<<q)-1),print(i,p&(-p)),flag=1; break; }
}
if (!flag) puts("-1");
}
return 0;
}