简化题意
(范围照CF上的给,BZOJ需要多组数据 T≤7 T ≤ 7 )给定一个长度为 n(n≤3e5) n ( n ≤ 3 e 5 ) 的排列,问你这个排列中是否存在 i,j,k(1≤i<j<k≤n) 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");
}