题解 P4734 【[BalticOI 2015]Hacker】

分析:

我们发现假如第一步选择位置 \(i\) ,那么系统操作者能把 \(\text{Byteasar}\) 限制成经过 \(i\) 的长度为 \(\lceil \dfrac{n}{2} \rceil\)

的任意一个序列。那么系统操作者肯定会选择价值最小的那个。

现在问题就是求出经过每个位置的长度为 \(\lceil \dfrac{n}{2} \rceil\)

的序列的价值的最小值,然后每个位置最小值的最大值就是答案。

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

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

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

区间覆盖线段树就可以了。

\(\text{code1}:\)

#include"cstdio"
#include"algorithm"
#define M 1000010
namespace IAKIOI{
	const int L=1<<20|1;
	char buffer[L],*S,*TT;
//	#define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,L,stdin),S==TT))?EOF:*S++)
	inline void read(int &x){
		x=0;int f=1;char s=getchar();
		while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
		while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
		x*=f;
	}
	inline void write(int x){
		if(x<0){putchar('-');x=-x;}
		if(x>9)write(x/10);
		putchar(x%10+'0');
	}
}
using namespace IAKIOI;
int n,a[M],s[M<<2],k,m,ans,la[M<<2];
struct node{
	int l,r,v;
}c[M];
bool cmp(node a,node b){
	return a.v>b.v;
}
void update(int x){
	s[x]=std::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;
}
inline 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(register int i=1;i<=m;i++)
		read(a[i]),a[i+m]=a[i];
	for(register int i=1;i<=n;i++)
		a[i]+=a[i-1];
	for(register int i=1;i<=m;i++)
		c[i]=node{i,i+k-1,a[i+k-1]-a[i-1]};
	std::sort(c+1,c+n+1,cmp);
	for(register 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 write(c[i].v),0;
	}
}

BUTT

线段树虽然能过,但是好慢啊。

我们发现,用线段树进行操作好像有点多余,其实完全可以只通过前缀和 \(+\) 二分的方式来维护序列。

再加一点点优化。。。

我们的简短的代码就完成力!线段树就是弱欸。

\(\text{code2}:\)

#include"cstdio"
#include"map"
#define M 500050
int T[M],a[M],a1[M],a2[M],n,len,ans;
namespace IAKIOI{
	const int L=1<<20|1;
	char buffer[L],*S,*TT;
	#define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,L,stdin),S==TT))?EOF:*S++)
	inline void read(int &x){
		x=0;int f=1;char s=getchar();
		while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
		while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
		x*=f;
	}
	inline void write(int x){
		if(x<0){putchar('-');x=-x;}
		if(x>9)write(x/10);
		putchar(x%10+'0');
	}
}
using namespace IAKIOI;
int main(){
	read(n),len=n+1>>1;
	for(int i=0;i<n;++i)
		read(a[i]),a1[i]=(i?a1[i-1]:0)+a[i];
	for(int i=0;i+len-1<n;++i)
		a2[i]=a1[i+len-1]-(i?a1[i-1]:0);
	for(int i=n-len+1;i<n;++i)
		a2[i]=a1[n-1]-a1[i-1]+a1[len-n+i-1];
	int con=std::max(n-1>>1,0),L=1,R=0;
	for(int i=n-con;i<n;T[++R]=i++)
		while(L<=R&&a2[T[R]]>=a2[i])--R;
	for(int i=0;i<n;++i){
		while(L<=R&&(i-T[L]+n)%n>con)++L;
		while(L<=R&&a2[T[R]]>=a2[i])--R;
		T[++R]=i,ans=std::max(ans,a2[T[L]]);
	}
	return write(ans),0;
}

完力。

posted @ 2020-10-18 13:35  Nakiri_Ayame_suki  阅读(389)  评论(0编辑  收藏  举报