题意:给你一个1~n的排列,问顺序(不要求连续)取三个数,是否可能为等差数列?n<=1W。
标程:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=10005; 4 const int can=31; 5 const int mod=20010531; 6 typedef long long ll; 7 int T,bit[N],Bit[N],pw[N],a[N],n; 8 int lowbit(int x){return x&(-x);} 9 void add(int x){int y=x;while (x<=n) bit[x]=((ll)bit[x]+pw[x-y])%mod,x+=lowbit(x);} 10 int sum(int x){int res=0,y=x;while (x) res=((ll)res+(ll)bit[x]*pw[y-x]%mod)%mod,x-=lowbit(x);return res;} 11 void Add(int x){int y=x;while (x) Bit[x]=((ll)Bit[x]+pw[y-x])%mod,x-=lowbit(x);} 12 int Sum(int x){int res=0,y=x;while (x<=n) res=((ll)res+(ll)Bit[x]*pw[x-y]%mod)%mod,x+=lowbit(x);return res;} 13 int qry(int x,int l){return ((ll)sum(x)-(ll)sum(x-l)*pw[l]%mod+mod)%mod;} 14 int Qry(int x,int l){return ((ll)Sum(x)-(ll)Sum(x+l)*pw[l]%mod+mod)%mod;} 15 int main() 16 { 17 pw[0]=1; 18 for (int i=1;i<N;i++) pw[i]=(ll)pw[i-1]*can%mod; 19 scanf("%d",&T); 20 while (T--) 21 { 22 scanf("%d",&n);memset(bit,0,sizeof(bit));memset(Bit,0,sizeof(Bit)); 23 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 24 int fl=0; 25 for (int i=1;i<=n;i++) 26 { 27 int len=min(a[i]-1,n-a[i]); 28 if (a[i]!=1&&a[i]!=n&&qry(a[i]-1,len)!=Qry(a[i]+1,len)) {fl=1;puts("Y");break;} 29 add(a[i]);Add(a[i]); 30 } 31 if (!fl) puts("N"); 32 } 33 return 0; 34 }
易错点:1.注意边界判断,a[i]!=1且a[i]!=n,而且判断回文注意左右两边的回文串长度一样。
2.树状数组上不能直接跳len步(与bit二分不同),需要用前缀和相减算。
题解:树状数组+hash
枚举等差数列的中间数x,也就是问该数前面出现过的一个数+后面出现的数是否可能=2*x。
用一个tag顺次扫,表示某个数是否出现。满足上面情况当且仅当存在不超过边界的y,使得tag[x-y]!=tag[x+y](一个出现,一个未出现),此时可以直接判Yes。考虑No的情况则是回文串。用hash进行比较是否回文,树状数组维护hash值的前缀和及后缀和来支持动态修改和区间查询。时间复杂度O(nlogn)。