CF1037H. Security

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(26nlgn)

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值