BZOJ 2124等差子序列 线段树&&hash
【题目描述 Description】
给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len>=3),使得 Ap1,Ap2,Ap3,…ApLen 是一个等差序列。
【输入描述 Input Description】
输入的第一行包含一个整数 T,表示组数。
下接 T 组数据,每组第一行一个整数 N,每组第二行为一个 1 到 N 的排列, 数字两两之间用空格隔开。
【输出描述 Output Description】
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一 行“N”。
【样例输入 Sample Input】
2
3
1 3 2
3
3 2 1
【样例输出 Sample Output】
N
Y
【数据范围及提示 Data Size & Hint】
对于5%的数据,N<=100,对于30%的数据,N<=1000,对于100%的数据,N<=10000,T<=7
【解题思路】
首先声明,此题开始并没有什么思路,只找到一个O(N^2)的算法,然而这并没有什么卵用。
老师明示暗示我要我用线段树去做,我苦思冥想没有想出来,于是就抄了题解。
题解是这样的,枚举等差中项,用一颗线段树去维护那些值选了,那些值没选,构成一个01串之后求一个哈希值。
如果出现中项左边的hash值和右边的hash值不一样的情况,就说明存在等差数列,因为证明有一个值在中项左边已经选过,并且与其对应的值在中项右边还没有选。
插入O(logn),查询O(logn),扫一遍O(n)整体O(ologn);
代码略丑
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn=10000+10, mod=100000007; int xp[maxn],a[maxn],n,v,t; long long sumv[4*maxn][2]; //sumv[i][0] 代表从左边扫的值,sumv[i][1]代表从右边扫的值 void updata(int u,int l,int r){ int lc=u<<1,rc=lc+1; if (l==r) sumv[u][0]=sumv[u][1]=1; else{ int mid=(l+r)/2; if (v<=mid) updata(lc,l,mid); else updata(rc,mid+1,r); sumv[u][0]=(sumv[rc][0]+xp[r-mid]*sumv[lc][0]%mod)%mod; sumv[u][1]=(sumv[lc][1]+xp[mid-l+1]*sumv[rc][1]%mod)%mod; } } long long query(int node,int l,int r,int a,int b,int x){ int lc=node<<1,rc=lc+1; if (l==a&&r==b) return sumv[node][x]; int mid=(l+r)/2; long long left=0,right=0; if (mid<b) right=query(rc,mid+1,r,max(mid+1,a),b,x); if (a<=mid) left=query(lc,l,mid,a,min(mid,b),x); return (x?left+right*xp[max(0,mid-a+1)]%mod:right+left*xp[max(0,b-mid)]%mod)%mod; } int main(){ scanf("%d",&t); for (int ii=0;ii<t;ii++){ memset(sumv,0,sizeof(sumv)); bool flag=0; scanf("%d",&n); xp[0]=1; for (int i=1;i<=n+5;i++) xp[i]=(xp[i-1]<<1)%mod; for (int i=0;i<n;i++)scanf("%d",&a[i]); for (int i=0;i<n;i++){ int x=a[i]; int len=min(x-1,n-x);//长度取短之后比较 if (len) { int t1=query(1,1,n,x+1,x+len,1); int t2=query(1,1,n,x-len,x-1,0); if (t1!=t2){ flag=1; break; } } v=x; updata(1,1,n); } if (flag) printf("Y\n"); else printf("N\n"); } }
以上为堆状线段树,由于我一直喜欢用结构体,所以就又打了一个,然后发现内存时间代码复杂度都比堆要差,大概是因为要建树和结构体太大的缘故。线段树的种类的确要视题目而定。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int maxn=10000+10,mod=100000007; 6 struct tree{ 7 int l,r,lch,rch; 8 long long sum; 9 }tr[maxn*2][2]; 10 //tr[now][0]代表从左往右, tr[now][1]代表从右往左 11 int cnt,n,t,xp[maxn],a[maxn]; 12 13 void build(int now,int l,int r){ 14 cnt++; 15 tr[cnt][0].l=tr[cnt][1].l=l; tr[cnt][0].r=tr[cnt][1].r=r; 16 if (l==r) return; 17 tr[cnt][0].lch=tr[cnt][1].lch=cnt+1; 18 int mid=(l+r)>>1; 19 build(cnt+1,l,mid); 20 tr[now][0].rch=tr[now][1].rch=cnt+1; 21 build(cnt+1,mid+1,r); 22 } 23 24 long long query(int now,int l,int r,int x){ 25 long long t1=0,t2=0; 26 if (tr[now][x].l==l&&tr[now][x].r==r) return tr[now][x].sum; 27 int mid=(tr[now][x].l+tr[now][x].r)>>1; 28 if (l<=mid) t1=query(tr[now][x].lch,l,min(r,mid),x)%mod; 29 if (r>mid) t2=query(tr[now][x].rch,max(mid+1,l),r,x)%mod; 30 if (x==0) return ((t1*xp[max(0,r-mid)])%mod+t2)%mod; 31 if (x==1) return ((t2*xp[max(mid-l+1,0)])%mod+t1)%mod; 32 //返回值的时候*xp的时候错过,乘的是数目,虽然我不知道我刚开始为什么写的不对 33 } 34 35 void insert(int now,int x){ 36 if (tr[now][0].l==x&&tr[now][0].r==x){ 37 tr[now][0].sum=tr[now][1].sum=1; 38 return; 39 } 40 int mid=(tr[now][0].l+tr[now][0].r)>>1; 41 if (x<=mid) insert(tr[now][0].lch,x); 42 if (x>=mid+1) insert(tr[now][0].rch,x); 43 int l=tr[now][0].l,r=tr[now][0].r; 44 tr[now][0].sum=((tr[tr[now][0].lch][0].sum*xp[r-mid])%mod 45 +tr[tr[now][0].rch][0].sum)%mod; 46 tr[now][1].sum=((tr[tr[now][1].rch][1].sum*xp[mid-l+1])%mod 47 +tr[tr[now][1].lch][1].sum)%mod; 48 } 49 50 int main(){ 51 scanf("%d",&t); 52 while (t--){ 53 memset(tr,0,sizeof(tr)); 54 cnt=0;//开始忘记清零CE了 55 scanf("%d",&n); 56 xp[0]=1; 57 bool flag=0; 58 for (int i=1;i<=n+5;i++) xp[i]=(xp[i-1]<<1)%mod;//预处理出所有二的幂 59 build(1,1,n); 60 for (int i=0;i<n;i++) scanf("%d",&a[i]); 61 for (int i=0;i<n;i++){ 62 int x=a[i]; 63 int len=min(a[i]-1,n-a[i]); 64 if (len&&query(1,x-len,x-1,0)!=query(1,x+1,x+len,1)){ 65 flag=1; 66 break; 67 } 68 insert(1,x); 69 } 70 if (flag) printf("Y\n"); 71 else printf("N\n"); 72 } 73 }