MemSQL Start[c]UP 2.0 Round 1 F.Permutation,[BZOJ2124]等差子序列(分治)

简化题意

  (范围照CF上的给,BZOJ需要多组数据 T7 T ≤ 7 )给定一个长度为 n(n3e5) n ( n ≤ 3 e 5 ) 的排列,问你这个排列中是否存在 i,j,k(1i<j<kn) i , j , k ( 1 ≤ i < j < k ≤ n ) ,使得 p[j]+p[j]=p[i]+p[k] p [ j ] + p [ j ] = p [ i ] + p [ k ]

分析

  据说有一种树状数组维护哈希值的做法,然而我并不会写这种做法,于是我就写了个类似分治的做法……具体做法我不太说得清楚..要不就请聪明的读者对着代码自行思考看看吧233..溜了溜了..

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
#define Pb push_back
typedef vector<int> vi;
const int maxn=300005;
int n;
vi arr,sufmx,sufmn;
inline void Add(vi &x) {
    for(int i=0;i<(int)x.size();++i)
        ++x[i];
}
inline void Sub(vi &x) {
    for(int i=0;i<(int)x.size();++i)
        --x[i];
}
inline bool Check(vi x) {
    int k=x.size(),mx=-1e9,mn=1e9;
    sufmx.clear();
    sufmx.resize(k);
    sufmn.clear();
    sufmn.resize(k);
    for(int i=k-1;~i;--i) {
        if(x[i]&1)
            mx=max(mx,x[i]),mn=min(mn,x[i]);
        sufmx[i]=mx,sufmn[i]=mn;
    }
    mx=-1e9,mn=1e9;
    for(int i=0;i<k;++i)
        if(x[i]&1)
            mx=max(mx,x[i]),mn=min(mn,x[i]);
        else {
            if(sufmn[i]<1e8&&mn<1e8)
                if(mn+sufmn[i]<=x[i]+x[i]&&x[i]+x[i]<=mx+sufmx[i])
                    return 1;
        }
    return 0;
}
inline bool Divide(vi x) {
    if(x.size()<=2)
        return 0;
    if(Check(x))
        return 1;
    Sub(x);
    if(Check(x))
        return 1;
    Add(x);
    vi l,r;
    for(int i=0;i<(int)x.size();++i)
        if(x[i]&1)
            l.push_back((x[i]+1)>>1);
        else
            r.push_back(x[i]>>1);
    return Divide(l)|Divide(r); 
}
int main() {
    read(n);
    for(int i=0,x;i<n;++i)
        read(x),arr.Pb(x);
    puts(Divide(arr)?"YES":"NO"); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值