Description
给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列。
Input
输入的第一行包含一个整数T,表示组数。下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
Output
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。
Sample Input
2
3
1 3 2
3
3 2 1
3
1 3 2
3
3 2 1
Sample Output
N
Y
Y
HINT
对于100%的数据,N<=10000,T<=7
Source
这个题好妙啊;
题目是要找到 i<j<k,使得a[j]-a[i]=a[k]-a[j];
我们考虑按顺序插入a[],对于我们当前位置j,如果有一个a[i]已经出现了,但是a[k]还没有出现,因为是排列,所以这个a[k]必然在后面,所以答案为"Y;
我们用一个辅助数组b[],按顺序如果x出现了,就标记为1,那么如果一个数x满足条件,那么必然有b[x-y]!=b[x+y],那么只需要判断以x为中心的最长的字符串是否为回文串即可;
以为如果不是回文串那么必然能找到一个b[x-y]!=b[x+y],所以答案为"Y",判断回文串可以用正反两边hsh,然后hsh值要动态修改,所以用树状数组和线段树都可以;
如果用线段树的话就是提取hsh值的时候在递归左区间的时候*pre[r-mid],我自己写的是树状数组,涉及单点修改和前缀查询,只不过在修改和询问的时候都要*pre[];
//MADE BY QT666 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=100050; int pre[N],n; int lowbit(int x){return x&-x;} struct data{ int hsh[N]; void update(int x){ for(int i=x;i<=n;i+=lowbit(i)) hsh[i]+=pre[i-x]; } int query(int x){ int ret=0; for(int i=x;i;i-=lowbit(i)) ret+=hsh[i]*pre[x-i]; return ret; } int ask(int l,int r){ return query(r)-query(l-1)*pre[r-l+1]; } }bit,bit2; int main(){ int T;scanf("%d",&T); pre[0]=1;for(int i=1;i<=10050;i++) pre[i]=pre[i-1]*3; while(T--){ scanf("%d",&n);int flg=0; memset(bit.hsh,0,sizeof(bit.hsh)); memset(bit2.hsh,0,sizeof(bit2.hsh)); for(int i=1;i<=n;i++){ int x;scanf("%d",&x); int len=min(x-1,n-x);if(flg) continue; if(len&&bit.ask(x-1-len+1,x-1)!=bit2.ask(n-x-len+1,n-x)) {puts("Y"),flg=1;} bit.update(x);bit2.update(n-x+1); } if(!flg) puts("N"); } return 0; }