P2757 [国家集训队] 等差子序列 题解

很巧妙的一道题,看到标签的时候想到始终想不到怎么用到哈希,但仔细分析出来后又发现每一步都还算环环相扣,于是写一篇题解。

根据题目,我们要找长度大于等于 \(3\) 的的等差序列,不难发现如果有长度大于 \(3\) 的等差序列,必然有长度等于 \(3\) 的等差序列,那我们只要找长度等于 \(3\) 的等差序列就行了,简化了问题。

考虑这样的序列有什么性质,首先,我们令中间的数为 \(a\),那么存在一个 \(x\) 使 \(a-x,a,a+x\) 构成这个合法序列,由于每一个数作为中间的数都是可能的,在枚举中间数这个过程是不能优化的,考虑怎么去找两边的数。

由于原序列是一个排列,每个数都只会出现一次,那么我们是可以在枚举到 \(a\) 时得知哪些数出现过,哪些数没有的,考虑将这个出现关系表示为 \(01\) 序列,表示令排列的长度为 \(n\),对于 \(a\) 的位置 \(i\),我们需要考虑的序列是以 \(i\) 为中心向两边延申到边界停止的所有的数构成的,如对于 \(n=7,i=5\) 序列的范围就是 \(3\)\(7\)

在这样一个关系里,关于 \(i\) 对称的两个数 \(i-k,i+k\) 若都为 \(1\)\(0\) 说明它们都在 \(i\) 的左边或右边,是不合法的,若要满足整个序列所有关于 \(i\) 对称的数都不合法,那么这个序列是一个回文串。如何快速判断回文?这就用到哈希了,至于修改哈希和查询哈希就用到了线段树,那么这道题就在 \(O(n\log n)\) 的时间内解决了。

机房神犇说这道题好像卡自然溢出?但好像没卡?

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Hash=13331;
const int P=1e9+7;
const int N=5e5+10;
struct SG{
	int l,r;
	int sum;
}tr1[N<<2],tr2[N<<2];
int T;
int n;
int a[N];
int h[N];
void pushup(int u){
	tr1[u].sum=(tr1[u<<1].sum*h[(tr1[u<<1|1].r-tr1[u<<1|1].l+1)]%P+tr1[u<<1|1].sum)%P;
	tr2[u].sum=(tr2[u<<1|1].sum*h[(tr2[u<<1].r-tr2[u<<1].l+1)]%P+tr2[u<<1].sum)%P;
}
void build(int u,int l,int r){
	tr1[u].l=tr2[u].l=l;
	tr1[u].r=tr2[u].r=r;
	if(l==r){
		tr1[u].sum=0;
		tr2[u].sum=0;
		return ;
	}
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}
void modify(int u,int x){
	if(tr1[u].l==x&&tr1[u].r==x){
		tr1[u].sum=1;
		tr2[u].sum=1;
		return ;
	}
	int mid=tr1[u].l+tr1[u].r>>1;
	if(x<=mid) modify(u<<1,x);
	if(x>mid) modify(u<<1|1,x);
	pushup(u);
}
int query1(int u,int l,int r){
	if(l==tr1[u].l&&r==tr1[u].r){
		return tr1[u].sum;
	}
	int mid=tr1[u].l+tr1[u].r>>1;
	if(r<=mid){
		return query1(u<<1,l,r);
	}
	else if(l>mid){
		return query1(u<<1|1,l,r);
	}
	else{
		return (query1(u<<1,l,mid)*h[r-mid]%P+query1(u<<1|1,mid+1,r))%P;
	}
}
int query2(int u,int l,int r){
	if(l==tr2[u].l&&r==tr2[u].r){
		return tr2[u].sum;
	}
	int mid=tr2[u].l+tr2[u].r>>1;
	if(r<=mid){
		return query2(u<<1,l,r);
	}
	else if(l>mid){
		return query2(u<<1|1,l,r);
	}
	else{
		return (query2(u<<1,l,mid)+query2(u<<1|1,mid+1,r)*h[mid-l+1]%P)%P;
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);    cout.tie(0);
	int T;
	cin>>T;
	h[0]=1;
	for(int i=1;i<=5e5;i++){
		h[i]=h[i-1]*Hash%P;
	}
	while(T--){
		int n;
		cin>>n; 
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		build(1,1,n);
		int flag=0;
		for(int i=1;i<=n;i++){
			modify(1,a[i]); 
			if(a[i]==1||a[i]==n){
				continue;
			} 
			int l,r;
			if(a[i]<=n/2){
				l=1;
				r=(a[i]+(a[i]-l));
			}
			else{
				r=n;
				l=(a[i]-(r-a[i]));
			}
			if(query1(1,l,r)!=query2(1,l,r)){
				flag=1;
				break;
			}
		}
		if(flag==1){
			cout<<"Y"<<endl;
		}
		else{
			cout<<"N"<<endl;
		}
	}
	return 0;
} 
posted @ 2025-05-26 10:38  Zom_j  阅读(35)  评论(0)    收藏  举报