P2757 [國家集訓隊]等差子序列(線段樹+hash/bitset)

題目鏈接

P2757 [國家集訓隊]等差子序列

題意:

給定一個排列,在其中找到一個長度大於 33 的等差數列
多組數據,n<=1e4(n<=1e4)

思路:

其實就要判斷是否有長度等於 33 的等差數列即可。由於是一個排列,我們從左往右依次掃描每個數字,對於每一個出現一個數字,就把其對應位置置 11 ,對於每一個數字 a[i]a[i] ,若爲等差數列的中間項,那麼必然存在一個 xx 使得位置 a[i]xa[i]-xa[i]+xa[i]+x 的值不一樣,故對於以 a[i]a[i] 爲中心的字符串若爲迴文串則以 a[i]a[i] 爲中心的等差數列不存在,否則存在。那麼任務即是怎樣判斷,可以用線段樹維護正向 0101 串的 hashhash 值和逆向的 hashhash 值,然後從左往右每次更新完進行判斷即可。
還有一種方法就是利用bitset來直接判斷。
a,b,ca,b,c 爲等差數列,那麼2b=a+c2*b=a+c,那麼我們就從左往右掃描,用每一個 a[i]a[i] 做爲 bb ,將當前的bitsetbitset往左以2b2*b,判斷是否和未掃描到的有重合的部分,若有則說明可以構成等差數列。

代碼:

線段樹+hash

#include <bits/stdc++.h>
#define ls x<<1
#define rs x<<1|1
#define ull unsigned long long
using namespace std;
const int N=1e4+10;
const int base=2333;
int T,n;
ull p[N],vl[N*4],vr[N*4];
void add(int x,int l,int r,int pos){
	if(l==r){
		vl[x]=vr[x]=1;return;
	}
	int mid=(l+r)/2;
	if(pos<=mid)add(ls,l,mid,pos);else add(rs,mid+1,r,pos);
	vl[x]=vl[ls]*p[r-mid]+vl[rs];
	vr[x]=vr[rs]*p[mid-l+1]+vr[ls];
}
ull query(int x,int l,int r,int LL,int RR,int id){
	if(l>=LL&&r<=RR){
		if(id==1)return vl[x];else return vr[x];
	}
	int mid=(l+r)/2;
	if(LL>mid)return query(rs,mid+1,r,LL,RR,id);
	else if(RR<=mid)return query(ls,l,mid,LL,RR,id);
	else{
		if(id==1)return query(ls,l,mid,LL,RR,id)*p[min(RR,r)-mid]+query(rs,mid+1,r,LL,RR,id);//記得控制範圍
		else return query(rs,mid+1,r,LL,RR,id)*p[mid-max(LL,l)+1]+query(ls,l,mid,LL,RR,id);//記得去max和min
	}
}
bool pd(int pos){
	int len=min(pos,n-pos+1);
	ull t1=query(1,1,n,pos,pos+len-1,1);
	ull t2=query(1,1,n,pos+1-len,pos,2);
	if(t1!=t2)return 1;else return 0;
}
int main()
{
	scanf("%d",&T);
	p[0]=1;for(int i=1;i<N;i++)p[i]=p[i-1]*base;
	while(T--){
		memset(vl,0,sizeof(vl));memset(vr,0,sizeof(vr));//注意初始化
		scanf("%d",&n);int flag=0;
		for(int i=1,x;i<=n;i++){
			scanf("%d",&x);
			if(flag)continue;
			add(1,1,n,x);
			if(pd(x)){
				flag=1;
			}
		}
		if(flag)puts("Y");else puts("N");
	}
}

bitset

#include <bits/stdc++.h>
using namespace std;
const int N=2e4+10;
int T,n;
int a[N];
bool pd(){
	bitset<N>t1,t2;
	for(int i=1;i<=n;i++)t1[a[i]]=1;
	for(int i=1;i<=n;i++){
		t1[a[i]]=0;
		if(((t2>>(N-2*a[i]))&t1).any())return 1;//以a[i]爲中點進行判斷,a+c=2*b
		t2[N-a[i]]=1;
	}
	return 0;
}
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		if(pd())puts("Y");
		else puts("N");
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章