jzoj5557 寫詩

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");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章