【BZOJ2124】等差子序列
Description
给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3),
使得Ap1,Ap2,Ap3,…ApLen是一个等差序列。
Input
输入的第一行包含一个整数T,表示组数。
下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
N<=10000,T<=7
Output
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。
Sample Input
2
3
1 3 2
3
3 2 1
3
1 3 2
3
3 2 1
Sample Output
N
Y
Y
题解:显然我们只要让len=3就行。考虑枚举中间数,用桶维护之前已经出现过的数。我们将桶看成一个01串,如果当前数是v[i],考虑桶中v[i]左右两边的串。如果存在v[i]-j和v[i]+j在桶中的存在情况不同,则表明找到了一个等差子序列。即,如果不存在等差子序列,则桶中v[i]的左右两边一定是对称的。用树状数组维护桶的正反hash值即可。
我才不会告诉你这题直接用bitset就能过呢~
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const ll P=1000000009;
const int maxn=10010;
int n;
int v[maxn];
ll bs[maxn];
struct node
{
ll s[maxn];
inline void updata(int x,ll val)
{
for(int i=x;i<=n;i+=i&-i) s[i]=(s[i]+val)%P;
}
inline ll query(int x)
{
ll ret=0;
for(int i=x;i;i-=i&-i) ret=(ret+s[i])%P;
return ret;
}
}s1,s2;
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void work()
{
n=rd();
int i,a;
for(i=1;i<=n;i++) v[i]=rd();
memset(s1.s,0,sizeof(s1.s)),memset(s2.s,0,sizeof(s2.s));
for(bs[0]=1,i=1;i<=n;i++) bs[i]=bs[i-1]*131%P;
for(i=1;i<=n;i++)
{
a=min(v[i]-1,n-v[i]);
if((s1.query(v[i]+a)-s1.query(v[i])+P)*bs[n-v[i]+1]%P!=(s2.query(n-v[i]+1+a)-s2.query(n-v[i]+1)+P)*bs[v[i]]%P)
{
printf("Y
");
return ;
}
s1.updata(v[i],bs[v[i]]),s2.updata(n-v[i]+1,bs[n-v[i]+1]);
}
printf("N
");
}
int main()
{
int T=rd();
while(T--) work();
return 0;
}//2 3 1 3 2 3 3 2 1