Scx117
只一眼,便辽阔了时间。

题意:给你一个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)。

posted on 2018-04-24 22:45  Scx117  阅读(162)  评论(0编辑  收藏  举报