P2757 [国家集训队]等差子序列

Captain_Paul

2018-09-18 16:36:09

Personal

这个题数据给的很小,$N<=10000$ 暴力就是开一个桶记录每一个数的位置 枚举首项、公差,判断即可 这样就可以拿到$45$分的好成绩 ~~如果你常数够小的话可以得到$50$或$55$~~ 讲一下$100$分做法: 这是一个$1$到$n$的排列 用一个$01$串来表示各个数字的出现情况 例如序列为${1,6,4,2,5,3}$,从前往后扫到$2$的时候 $01$串长这样:${110101}$ 可以发现,如果以一个出现的数为中心,两边对称的地方有$1$,则存在等差数列 用线段树或树状数组维护$hash$值 从左往右扫,对于每一个$a_i$查询它两边的$hash$值是否相等 如果不相等,那么后面一定会有数补过来形成等差数列,输出$Y$即可 所以区间查询单点修改,总复杂度$O(nlogn)$ $CF452F$也是这个题,不过数据范围$3e5$嘿嘿嘿 ``` #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define reg register using namespace std; typedef unsigned long long ll; const int N=1e4+5,base=127; int n,a[N]; ll pw[N],hs1[N<<2],hs2[N<<2]; inline int read() { int x=0,w=1; char c=getchar(); while (!isdigit(c)&&c!='-') c=getchar(); if (c=='-') c=getchar(),w=-1; while (isdigit(c)) { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x*w; } inline void pushup(int now,int l,int r) { hs1[now]=(hs1[now<<1]*pw[r]+hs1[now<<1|1]); hs2[now]=(hs2[now<<1]+hs2[now<<1|1]*pw[l]); } void update(int l,int r,int now,int x) { if (l==r){hs1[now]=hs2[now]=1; return;} int mid=(l+r)>>1; if (x<=mid) update(l,mid,now<<1,x); else update(mid+1,r,now<<1|1,x); pushup(now,mid-l+1,r-mid); } ll query1(int L,int R,int l,int r,int now) { if (l>R||r<L) return 0; if (l>=L&&r<=R) return hs1[now]; int mid=(l+r)>>1; if (mid>=R) return query1(L,R,l,mid,now<<1); if (mid<L) return query1(L,R,mid+1,r,now<<1|1); return (query1(L,mid,l,mid,now<<1)*pw[R-mid]+query1(mid+1,R,mid+1,r,now<<1|1)); } ll query2(int L,int R,int l,int r,int now) { if (l>R||r<L) return 0; if (l>=L&&r<=R) return hs2[now]; int mid=(l+r)>>1; if (mid>=R) return query2(L,R,l,mid,now<<1); if (mid<L) return query2(L,R,mid+1,r,now<<1|1); return (query2(L,mid,l,mid,now<<1)+query2(mid+1,R,mid+1,r,now<<1|1)*pw[mid-L+1]); } int main() { pw[0]=1; for (reg int i=1;i<=10000;i++) pw[i]=pw[i-1]*base; for (reg int T=read();T;T--) { memset(hs1,0,sizeof(hs1)); memset(hs2,0,sizeof(hs2)); n=read(); bool flag=0; for (reg int i=1;i<=n;a[i++]=read()); if (n<3) {puts("N"); continue;} for (reg int i=1;i<=n;i++) { int len=min(a[i]-1,n-a[i]); if (query1(a[i]-len,a[i]-1,1,n,1)!=query2(a[i]+1,a[i]+len,1,n,1)){flag=1; break;} update(1,n,1,a[i]); } if (flag) puts("Y"); else puts("N"); } return 0; } ```