题目描述
给一个1到N的排列{Ai},询问是否存在
1≤p1<p2<p3<p4<p5<…<pLen≤N(Len≥3)
使得Ap1,Ap2,Ap3,⋯,ApLen是一个等差序列。
输入格式:
输入的第一行包含一个整数T,表示组数。
下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
输出格式:
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。
说明
对于5%的数据,N<=100
对于30%的数据,N<=1000
对于100%的数据,N<=10000,T<=7
题解:
排列:每个数出现且仅出现一次。
考虑从左到右枚举等差中项b(数值),在在b左边的数状态记为0,b右边的数状态记为1,。
考虑如果没有等差数列,那么b+k和b-k在同侧,即同为1或0,可以构成回文串。
对于回文串的判断,可以用数值hash,正反做一遍即可。
现在考虑枚举下一个等差中项时,如何利用现在的状态。
可以用线段树存下正反hash值,每次枚举下一个就单点修改,判断就是区间查询。
区间合并就是 val左*base^(右区间长度)+val右;
查询的合并要对查询右边界和右区间边界取min
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define ull unsigned long long const int maxn=100005; const ull base=1000007; int T,n; int num1,num2,root1,root2; int a[maxn],a_pos,a_l,a_r; ull b[maxn]; struct tree{ ull val; int ls,rs; }t1[maxn<<2],t2[maxn<<2]; void update1(int rt,int len){ t1[rt].val=t1[t1[rt].ls].val*b[len]+t1[t1[rt].rs].val; } void build1(int &rt,int l,int r){ rt=++num1; if(l==r){ t1[rt].val=1; return ; } int mid=(l+r)>>1; build1(t1[rt].ls,l,mid); build1(t1[rt].rs,mid+1,r); update1(rt,r-mid); } void update2(int rt,int len){ t2[rt].val=t2[t2[rt].ls].val*b[len]+t2[t2[rt].rs].val; } void build2(int &rt,int l,int r){ rt=++num2; if(l==r){ t2[rt].val=1; return ; } int mid=(l+r)>>1; build2(t2[rt].ls,l,mid); build2(t2[rt].rs,mid+1,r); update2(rt,r-mid); } void modify1(int rt,int l,int r){ if(l==r){ t1[rt].val=0; return ; } int mid=(l+r)>>1; if(a_pos<=mid) modify1(t1[rt].ls,l,mid); else modify1(t1[rt].rs,mid+1,r); update1(rt,r-mid); } void modify2(int rt,int l,int r){ if(l==r){ t2[rt].val=0; return ; } int mid=(l+r)>>1; if(a_pos<=mid) modify2(t2[rt].ls,l,mid); else modify2(t2[rt].rs,mid+1,r); update2(rt,r-mid); } ull querry1(int rt,int l,int r){ if(a_l<=l&&r<=a_r) return t1[rt].val; int mid=(l+r)>>1; if(a_r<=mid) return querry1(t1[rt].ls,l,mid); else if(a_l>mid) return querry1(t1[rt].rs,mid+1,r); else return querry1(t1[rt].ls,l,mid)*b[min(a_r,r)-mid]+querry1(t1[rt].rs,mid+1,r); } ull querry2(int rt,int l,int r){ if(a_l<=l&&r<=a_r) return t2[rt].val; int mid=(l+r)>>1; if(a_r<=mid) return querry2(t2[rt].ls,l,mid); else if(a_l>mid) return querry2(t2[rt].rs,mid+1,r); else return querry2(t2[rt].ls,l,mid)*b[min(a_r,r)-mid]+querry2(t2[rt].rs,mid+1,r); } void nice(){ num1=num2=root1=root2=0; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build1(root1,1,n); build2(root2,1,n); for(int i=2;i<n;i++){ a_pos=a[i-1]; modify1(root1,1,n); a_pos=n-a[i-1]+1; modify2(root2,1,n); ull ret1,ret2; int len=min(a[i]-1,n-a[i]); if(!len) continue; a_r=a[i]-1;a_l=a[i]-len; ret1=querry1(root1,1,n); a_r=n-a[i];a_l=a_r-len+1; ret2=querry2(root2,1,n); if(ret1!=ret2) {printf("Y ");return ;} } printf("N "); } int main(){ b[0]=1; for(int i=1;i<=100000;i++) b[i]=b[i-1]*base; scanf("%d",&T); while(T--) nice(); }