LOJ
我们发现假如第一步选择位置(i),那么系统操作者能把( m Byteasar)限制成经过(i)的长度为(lceil frac{n}{2} ceil)的任意一个序列。那么系统操作者肯定会选择价值最小的那个。
现在问题就是求出经过每个位置的长度为(lceil frac{n}{2} ceil)的序列的价值的最小值,然后每个位置最小值的最大值就是答案。
现在考虑怎么求出这个最大值。
我们发现这样的序列一共只有(n)个,我们可以对这(n)个序列的价值从大到小排个序。
然后对每个序列的范围做一下区间覆盖。显然当一个位置被覆盖了(lceil frac{n}{2} ceil)次的时候,当前的序列的价值就是答案。
区间覆盖线段树就可以完美解决。
代码:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
#define rg register
void read(int &x){
char ch;bool ok;
for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
}
const int maxn=1e6+10;
int n,a[maxn],s[maxn*4],k,m,ans,la[maxn*4];
struct oo{int l,r,v;}c[maxn];
bool cmp(oo a,oo b){return a.v>b.v;}
void update(int x){s[x]=max(s[x<<1],s[x<<1|1]);}
void pushdown(int x){
la[x<<1]+=la[x],la[x<<1|1]+=la[x];
s[x<<1]+=la[x],s[x<<1|1]+=la[x];
la[x]=0;
}
void change(int x,int l,int r,int a,int b){
if(a<=l&&b>=r)return s[x]++,la[x]++,void();
int mid=(l+r)>>1;if(la[x])pushdown(x);
if(a<=mid)change(x<<1,l,mid,a,b);
if(b>mid)change(x<<1|1,mid+1,r,a,b);
update(x);
}
int main(){
read(n);m=n;n<<=1;k=(m+1)/2;
for(rg int i=1;i<=m;i++)read(a[i]),a[i+m]=a[i];
for(rg int i=1;i<=n;i++)a[i]+=a[i-1];
for(rg int i=1;i<=m;i++)c[i]=(oo){i,i+k-1,a[i+k-1]-a[i-1]};
sort(c+1,c+n+1,cmp);
for(rg int i=1;i<=m;i++){
if(c[i].r<=m)change(1,1,m,c[i].l,c[i].r);
else change(1,1,m,c[i].l,m),change(1,1,m,1,c[i].r-m);
if(s[1]==k)return printf("%d
",c[i].v),0;
}
}