QOJ 8079

传送门

注意到一个事情,如果 \(x\)\(s_i\) 的周期 \((x<i)\)

那么 \(x\)\(s_{i-1}\) 的周期。

由此又可以推出,若 \(x\) 不是 \(s_i\) 的周期 \((x\le i)\),则 \(x\) 也不是 \(s_{i+1}\) 的周期。

那么从 \(s_x\) 开始,存在周期 \(x\)\(s_i\) 是连续的,即存在 \(r\) 使得对于 \(i\in [x,r_x]\) 都满足 \(s_i\) 存在周期 \(x\)

判断周期等价于判断前后缀,由此容易 二分+哈希 对每个 \(x\) 都求出 \(r_x\)

课上直接将题魔改成了对于每个 \(s_i\) 求最长 border,那想到这里后对于每个 \(s_i\) 用 set 从左到右扫一下求最小周期就做完了。但是原题略显复杂。

观察询问的限制。注意到询问等价于求出最小的 \(p_i\) 满足 \(i\in [l,r]\)\(r_{p_i}\ge k\)。如果询问结果大于 \(k\) 则无解。

这个问题也是容易做的。将询问离线下来再根据 \(k\) 从大到小排序,同时将所有 \(i\) 根据 \(r_{p_i}\) 排序,最后用线段树单点加区间 min 扫描一下即可。

code

#include <bits/stdc++.h>
//taskkill /f /im 未命名1.exe
#define ED cerr<<endl;
#define TS cerr<<"I AK IOI"<<endl;
#define cr(x) cerr<<x<<endl;
#define cr2(x,y) cerr<<x<<" "<<y<<endl;
#define cr3(x,y,z) cerr<<x<<" "<<y<<" "<<z<<endl;
#define cr4(x,y,z,w) cerr<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
#define print(a,l,r) for(int i=l;i<=r;++i) cerr<<a[i]<<' ';puts("");
#define popcnt __builtin_popcount
#define all(s) s.begin(),s.end()
#define bstring basic_string
//#define add(x,y) (x+=y)%=mod
#define pii pair<int,int>
#define epb emplace_back
#define pb push_back
#define mk make_pair
#define ins insert
#define fi first
#define se second
#define ll long long
//#define ull unsigned long long
using namespace std;
const int N=5e5+5,INF=2e9,mod=1e9+7,B=31;
int t,n,m,k;
char s[N+N],_s[N];int hd,tl;
pii a[N];ll f[N+N],p[N];

ll get(int l,int r) {
	return (f[r]-f[l-1]*p[r-l+1]%mod+mod)%mod;
}

struct que {
	int l,r,k,id;
	bool operator<(const que &W) const {
		return k>W.k;
	}
}q[N];int ans[N],re[N];

struct upd {
	int x,y,v;
	bool operator<(const upd &W) const {
		return y>W.y;
	}
}ud[N];

struct tree {
	int l,r,mi;
}tr[N<<2];

void pushup(int u) {
	tr[u].mi=min(tr[u<<1].mi,tr[u<<1|1].mi);
}

void build(int u,int l,int r) {
	tr[u].l=l,tr[u].r=r,tr[u].mi=INF;
	if(l==r) return;
	int mid=l+r>>1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}

void update(int u,int ps,int x) {
	if(tr[u].l==tr[u].r) {
		tr[u].mi=x;return;
	}
	int mid=tr[u].l+tr[u].r>>1;
	if(ps<=mid) update(u<<1,ps,x);
	else update(u<<1|1,ps,x);
	pushup(u);
}

int query(int u,int l,int r) {
	if(l<=tr[u].l&&tr[u].r<=r) {
		return tr[u].mi;
	}
	int mid=tr[u].l+tr[u].r>>1,res=INF;
	if(l<=mid) res=min(res,query(u<<1,l,r));
	if(r>mid) res=min(res,query(u<<1|1,l,r));
	return res;
}

void sol() {
	scanf("%d",&n);
	scanf("%s",_s+1);hd=n+1,tl=n;
	for(int i=1;i<=n;++i) {
		if(_s[i]>='A'&&_s[i]<='Z') {
			s[++tl]=_s[i]-'A'+'a';
		}
		else s[--hd]=_s[i];
		a[i]={hd,tl};
	}
	f[hd-1]=0,p[0]=1;
	for(int i=hd;i<=tl;++i) {
		p[i-hd+1]=p[i-hd]*B%mod;
		f[i]=(f[i-1]*B+s[i]-'a')%mod;
	}
	for(int i=1;i<=n;++i) {
		int l=i,r=n,ans=i;
		while(l<=r) {
			int mid=l+r>>1;
			int L=a[mid].fi,R=a[mid].se;
			if(get(L,R-i)==get(L+i,R)) {
				ans=mid,l=mid+1;
			}
			else r=mid-1;
		}
		re[i]=ans;
	}
	scanf("%d",&m);int x;
	for(int i=1;i<=m;++i) {
		scanf("%d",&x);
		ud[i]={i,re[x],x};
	}
	scanf("%d",&k);
	for(int i=1;i<=k;++i) {
		scanf("%d%d%d",&q[i].k,&q[i].l,&q[i].r);
		q[i].id=i;
	}
	sort(q+1,q+1+k),sort(ud+1,ud+1+m);
	build(1,1,m);
	for(int i=1,j=1;i<=k;++i) {
		while(j<=m&&ud[j].y>=q[i].k) {
			update(1,ud[j].x,ud[j].v),++j;
		}
		int res=query(1,q[i].l,q[i].r),id=q[i].id;
		if(res>q[i].k) ans[id]=-1;
		else ans[id]=res;
	}
	for(int i=1;i<=k;++i) {
		printf("%d\n",ans[i]);
	}
}

int main()
{
	t=1;
	while(t--) {
		sol();
	}
	return 0;
}
posted @ 2025-07-21 20:25  Oier_szc  阅读(11)  评论(0)    收藏  举报