Description
给一个
1
1
到的排列
Ai
A
i
,询问是否存在
1≤p1<p2<p3<p4<p5<⋯<pLen≤N
1
≤
p
1
<
p
2
<
p
3
<
p
4
<
p
5
<
⋯
<
p
L
e
n
≤
N
(3≤len)
(
3
≤
l
e
n
)
,使得
Ap1,Ap2,Ap3,⋯,ApLen
A
p
1
,
A
p
2
,
A
p
3
,
⋯
,
A
p
L
e
n
是一个等差序列
Input
输入的第一行包含一个整数
T
T
,表示组数.
下接组数据,每组第一行一个整数
N
N
,每组第二行为一个到
N
N
的排列,数字两两之间用空格隔开
Output
对于每组数据,如果存在一个等差子序列,则输出一行”Y”,否则输出一行”N”.
Sample Input
2
3
1 3 2
3
3 2 1
Sample Output
N
Y
Data Size & Hint
Solution
要求一个 len≥3 l e n ≥ 3 的等差子序列,那还不如直接求 len=3 l e n = 3 的等差子序列
考虑等差子序列的性质
a1+a3=2a2
a
1
+
a
3
=
2
a
2
设中项为
x
x
,易得左侧有一点,右侧有一点
x−d
x
−
d
,
1<abs(d)<x
1
<
a
b
s
(
d
)
<
x
如果
x+d,x−d
x
+
d
,
x
−
d
没有出现在
x
x
的同一侧,那么显然的,必然会出现的等差子序列
考虑维护一侧的数(没有出现的就在另一侧)
当前询问到第
i
i
个位置,为
在
1−n
1
−
n
数轴上标记已经出现过的数
每次从数轴上点
pi
p
i
开始向两端扩展
(l=r=i,l−−,r++)
(
l
=
r
=
i
,
l
−
−
,
r
+
+
)
若
pi
p
i
为中心两端对称分布
(0−0,1−1)
(
0
−
0
,
1
−
1
)
(忽略多余部分),则说明
pi+d,pi−d
p
i
+
d
,
p
i
−
d
都出现在
pi
p
i
的同一侧(全0即右侧,全1即左侧),不存在以
i
i
位置为中心的等差子序列
否则存在以位置为中心的等差子序列
考虑如何维护左右部分是否对称
要求:单点修改,区间求和
树状数组或线段树即可
开两个同时维护正向与反向,每次提取一段对比即可
lenth=min(n−a[i],a[i]−1);
l
e
n
t
h
=
m
i
n
(
n
−
a
[
i
]
,
a
[
i
]
−
1
)
;
正向区间
a[i],a[i]+lenth
a
[
i
]
,
a
[
i
]
+
l
e
n
t
h
反向区间
n−a[i]+1,n−a[i]+1+lenth
n
−
a
[
i
]
+
1
,
n
−
a
[
i
]
+
1
+
l
e
n
t
h
若相等,则不存;若不等,则存在
单点修改线段树直接维护就行
记得update比较特殊,需要乘上一个相对位置
具体看代码.
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define L (x<<1)
#define R (x<<1)+1
#define mid ((l+r)>>1)
const int N = 100010;
const ll mod = 19260817;
int n,a[N];
ll p[N];
struct tree {
ll node[N<<4],siz[N];
void clear() {
memset(node,0,sizeof(node));
memset(siz,0,sizeof(siz));
}
void update(int x) {node[x]=(node[L]*p[siz[R]]%mod+node[R])%mod;}
void build(int x,int l,int r) {
if(l!=r) {
build(L,l,mid);
build(R,mid+1,r);
siz[x]=siz[L]+siz[R];
}
else siz[x]=1;
}
void change(int x,int p,int l,int r) {
if(l==r) {node[x]=1;return;}
if(p<=mid) change(L,p,l,mid);
else change(R,p,mid+1,r);
update(x);
}
ll query(int x,int l,int r,int _l,int _r) {
if(l>=_l && r<=_r) {return node[x]*p[_r-r]%mod;}
ll ans=0;
if(mid>=_l) ans+=query(L,l,mid,_l,_r);
if(mid<_r) ans+=query(R,mid+1,r,_l,_r);
ans%=mod;
return ans;
}
}t1,t2;
int read() {
int ans=0,flag=1;
char ch=getchar();
while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
if(ch=='-') {flag=-1;ch=getchar();}
while(ch>='0' && ch<='9') {ans=ans*10+ch-'0';ch=getchar();}
return ans*flag;
}
void init() {
n=read();p[0]=1;
t1.clear();t2.clear();
t1.build(1,1,n);t2.build(1,1,n);
for(int i=1;i<=n;++i) {
a[i]=read();
p[i]=p[i-1]*2%mod;
}
}
void work() {
bool flag=0;
for(int i=1;i<=n;++i) {
t1.change(1,a[i],1,n);
t2.change(1,n-a[i]+1,1,n);
int lenth=min(n-a[i],a[i]-1);
if(lenth && t1.query(1,1,n,a[i],a[i]+lenth) != t2.query(1,1,n,n-a[i]+1,n-a[i]+1+lenth)) {
puts("Y");
flag=1;
break;
}
}
if(!flag) puts("N");
}
int main() {
int t=read();
while(t--) {
init();
work();
}
return 0;
}