BZOJ 2124: 等差子序列 线段树维护hash
2124: 等差子序列
Description
给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列。
Input
输入的第一行包含一个整数T,表示组数。下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
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
HINT
对于100%的数据,N<=10000,T<=7
题解:
题目说了是1到n的排列
我们将1到n逐渐插入线段树的中,且用01表示出现状态
假设当前x,我们只要找出与x相距距离相等的存在状态不同的就说明存在答案
这就是线段树维护hash
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 10010 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define p 3 #define mod 1000000007 using namespace std; typedef long long ll; ll hash[N<<2],hash2[N<<2]; ll pow[N]; int a[N]; int n,t; void pushup(int rt,int m) { ll tmp=m>>1; hash[rt]=(hash[rt<<1]*pow[tmp]+hash[rt<<1|1])%mod; hash2[rt]=(hash2[rt<<1|1]*pow[m-tmp]+hash2[rt<<1])%mod; } void update(int pt,int l,int r,int rt) { if(l==r) { hash[rt]=hash2[rt]=1; return; } int mid=(l+r)>>1; if(pt<=mid)update(pt,lson); else update(pt,rson); pushup(rt,r-l+1); } ll query(int L,int R,int l,int r,int rt) { if(L>R)return 0; int ans=0; if(L==l&&r==R) { return hash[rt]; } int mid=(l+r)>>1; if(R<=mid)return query(L,R,lson); else if(L>mid)return query(L,R,rson); else return (query(L,mid,lson)*pow[R-mid]+query(mid+1,R,rson))%mod; } ll query2(int L,int R,int l,int r,int rt) { if(L>R)return 0; if(L==l&&r==R) { return hash2[rt]; } int mid=(l+r)>>1; if(R<=mid)return query2(L,R,lson); else if(L>mid)return query2(L,R,rson); else return (query2(L,mid,lson)+query2(mid+1,R,rson)*pow[mid-L+1])%mod; } int main() { scanf("%d",&t); pow[1]=p; for(int i=2;i<=10000;i++)pow[i]=(pow[i-1]*p)%mod; while(t--) { memset(hash,0,sizeof(hash)); memset(hash2,0,sizeof(hash2)); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); int flag=0; for(int i=1;i<=n;i++) { ll len=min(a[i]-1,n-a[i]); ll tmp1=query(a[i]-len,a[i]-1,1,n,1); ll tmp2=query2(a[i]+1,a[i]+len,1,n,1); if(tmp1!=tmp2) { flag=1;break; } update(a[i],1,n,1); } if(flag)printf("Y\n"); else printf("N\n"); } }