bzoj 2124: 等差子序列

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

Sample Output

N
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;
}
posted @ 2017-10-07 21:15  qt666  阅读(428)  评论(0编辑  收藏  举报