题目链接
P2757 [国家集训队]等差子序列
题意:
给定一个排列,在其中找到一个长度大于
3
3
3 的等差数列
多组数据,
(
n
<
=
1
e
4
)
(n<=1e4)
(n<=1e4)
思路:
其实就要判断是否有长度等于
3
3
3 的等差数列即可。由于是一个排列,我们从左往右依次扫描每个数字,对于每一个出现一个数字,就把其对应位置置
1
1
1 ,对于每一个数字
a
[
i
]
a[i]
a[i] ,若为等差数列的中间项,那么必然存在一个
x
x
x 使得位置
a
[
i
]
−
x
a[i]-x
a[i]−x 和
a
[
i
]
+
x
a[i]+x
a[i]+x 的值不一样,故对于以
a
[
i
]
a[i]
a[i] 为中心的字符串若为回文串则以
a
[
i
]
a[i]
a[i] 为中心的等差数列不存在,否则存在。那么任务即是怎样判断,可以用线段树维护正向
01
01
01 串的
h
a
s
h
hash
hash 值和逆向的
h
a
s
h
hash
hash 值,然后从左往右每次更新完进行判断即可。
还有一种方法就是利用bitset来直接判断。
若
a
,
b
,
c
a,b,c
a,b,c 为等差数列,那么
2
∗
b
=
a
+
c
2*b=a+c
2∗b=a+c,那么我们就从左往右扫描,用每一个
a
[
i
]
a[i]
a[i] 做为
b
b
b ,将当前的
b
i
t
s
e
t
bitset
bitset往左以
2
∗
b
2*b
2∗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");
}
}