Description
给出一个1到n的排列h
要求找出一个三元组满足0
Sample Input
输入样例1
4
1 3 4 2
输入样例2
5
1 5 2 4 3
Sample Output
输出样例1
NO
输出样例2
YES
Data Constraint
n<=3e5
Solution
今天的比赛中最可做的题目,然而还是只想到n^2的做法
看了题解之后恍然大悟
枚举中间的点j
设x=hi或hj
则有2*hj-x>=1,2*hj-x<=n
2*hj-n<=x<=2*hj-1
那我们每次枚举j的时候用树状数组维护符合上面不等式且在j左边的点
设点数为k,这些点的h值之和为sum
若k为奇数,则说明一定有一些点在j的右边,输出yes
若k为偶数
且sum能整除2*hj
则说明一定有一些点在j的左边,输出yes
记得开long long
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll N=300005;
ll n,i,j,fl,tr[N],t[N],a[N],k;
ll read(){
ll sum=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9'){
sum=sum*10+c-'0';
c=getchar();}
return sum;
}
void add(ll x,ll y){
ll k=x;
while (x<=n){
tr[x]+=y;
t[x]+=k;
x+=x&(-x);}
}
ll query(ll x){
int s=0;
while (x>0){
s+=tr[x];
x-=x&(-x);}
return s;
}
ll find(ll x){
ll s=0;
while (x>0){
s+=t[x];
x-=x&(-x);
}
return s;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
n=read();
fo(i,1,n) a[i]=read();
add(a[1],1);
fo(i,2,n-1){
k=query(min(n,2*a[i]-1))-query(max((ll)0,2*a[i]-n-1));
if (k%2==1) {
fl=1;
break;}
k=find(min(n,2*a[i]-1))-find(max((ll)0,2*a[i]-n-1));
if (k%(2*a[i])!=0) {
fl=1; break;}
add(a[i],1);
}
if (fl) printf("YES\n");
else printf("NO\n");
}