【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