「BalticOI 2015」黑客

LOJ

我们发现假如第一步选择位置\(i\),那么系统操作者能把\(\rm Byteasar\)限制成经过\(i\)的长度为\(\lceil \frac{n}{2} \rceil\)的任意一个序列。那么系统操作者肯定会选择价值最小的那个。

现在问题就是求出经过每个位置的长度为\(\lceil \frac{n}{2} \rceil\)的序列的价值的最小值,然后每个位置最小值的最大值就是答案。

现在考虑怎么求出这个最大值。

我们发现这样的序列一共只有\(n\)个,我们可以对这\(n\)个序列的价值从大到小排个序。

然后对每个序列的范围做一下区间覆盖。显然当一个位置被覆盖了\(\lceil \frac{n}{2} \rceil\)次的时候,当前的序列的价值就是答案。

区间覆盖线段树就可以完美解决。

代码:

#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\n",c[i].v),0;
    }
}

posted @ 2019-11-13 19:42  蒟蒻--lichenxi  阅读(264)  评论(0编辑  收藏  举报