Loading

CF573E Bear and Bowling(分块+斜率优化)

洛谷题目传送门

有一个贪心策略是维护下一个数字选择某一个位置的最优解,然和每次选择最优的来转移,把他选了,然后更新其他位置的代价
\(t_i\)表示\(i\)之前选的数字的个数,\(b_i\)表示\(i\)之后选的数字的\(a\)值之和
那么在\(i\)选择的代价是\(a_i\times t_i+b_i\),我们就是要最大化这个式子
考虑用分块维护这个东西,然后在每个块内建立一个凸包,然后就是斜率优化的套路
考虑设\(f_i=a_i\times t_i+b_i\),则\(b_i=-a_i\times t_i+f_i\)
相当于是用一条斜率为\(t_i\)的线,截若干形容\((-a_i,b_i)\)的点
为了方便维护,我们让整个块的\(t_i\)相同,然后随着选的数的增加,\(t\)的值会增加,所以最优价的位置不会向前移动
当选出一个数是x时,之前块的所有元素的\(b_i\)都会加上\(a_x\),之后所有块的\(t_i\)都会加1
因为是整块加减,所以可以打标记,因为整体加相当于将所有点平移,而斜率不会发生改变
所以不会影响斜率的查询
至于\(x\)这个块,因为不是整体平移,斜率会改变,所以把整个块重构即可
总复杂度\(O(n\sqrt n)\)
略微卡常

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 1e15;
typedef double db;
const LL N = 2e5+7;
const LL Q = 500;
LL que[Q][Q],Head[Q],Tail[Q],St[Q],Ed[Q],Pos[N];
LL A[N],B[N],t[Q],Add[Q];
LL p[N];
LL len,cnt=0;
LL n;
LL cmp(LL a,LL b)
{
	return A[a]<A[b];
}
db slope(LL x,LL y)
{
	if(A[y]==A[x])
	{
		if(B[x]==B[y]) return 1;
		if(B[x]<B[y]) return INF;
		return -INF;
	}
	return (B[y]-B[x])/(A[y]-A[x]);
}

void Build(LL x)
{
	Head[x]=1;
	Tail[x]=0;
	LL l=St[x],r=Ed[x];
	for(LL o=l;o<=r;o++)
	{
		LL i=p[o];
		B[i]=B[i]+Add[x]+t[x]*A[i];
	}
	Add[x]=0;
	t[x]=0;
	for(LL o=l;o<=r;o++)
	{
		LL i=p[o];
		while(Head[x]<Tail[x]&&slope(que[x][Tail[x]-1],que[x][Tail[x]])<=slope(que[x][Tail[x]],i)) Tail[x]--;
		que[x][++Tail[x]]=i;
	}
//	cout<<x<<": "<<endl;
//	for(LL i=Head[x];i<=Tail[x];i++)
//	cout<<que[x][i]<<'-'<<A[que[x][i]]<<'-'<<B[que[x][i]]<<' ';
//	cout<<endl;
//	cout<<"---------"<<endl;
}
pair<LL,LL> Ask(LL x)
{
	while(Head[x]<Tail[x]&&slope(que[x][Head[x]],que[x][Head[x]+1])>=-t[x]) ++Head[x];
	if(Head[x]>Tail[x]) return make_pair(-INF,0);
//	cout<<que[x][Head[x]]<<' '<<Add[x]<<' '<<t[x]<<' '<<A[que[x][Head[x]]]<<endl;
	return make_pair(B[que[x][Head[x]]]+Add[x]+t[x]*A[que[x][Head[x]]],que[x][Head[x]]);
}
inline LL read()
{
    LL x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int main()
{
//	freopen("JOI.in","r",stdin);
//	freopen("JOI.out","w",stdout);
	scanf("%lld",&n);
	len=sqrt(n);
	if(len==0) len=1;
	if(n==1) len=1;
	for(LL i=1;i<=n;i++)
	{
		A[i]=read();
		B[i]=A[i];
		p[i]=i;
		Pos[i]=(i-1)/len+1;
		if(!St[Pos[i]]) St[Pos[i]]=i;
		Ed[Pos[i]]=max(Ed[Pos[i]],i);
		cnt=max(cnt,Pos[i]);
	}
	if(n==1)
	{
		cout<<max(0ll,A[1]);
		return 0;
	}
	for(LL i=1;i<=cnt;i++)
	{
		sort(p+St[i],p+Ed[i]+1,cmp);
		Build(i);
	}
	LL Ans=0,sum=0;
	for(LL i=1;i<=n;i++)
	{
		pair<LL,LL> ans(-INF,0);
		for(LL x=1;x<=cnt;x++)
		{
			pair<LL,LL> pos=Ask(x);
			if(pos.first>=ans.first) ans=pos;
		}
//		cout<<ans.first<<' '<<ans.second<<endl;
		sum+=ans.first;
		Ans=max(Ans,sum);
		LL r=ans.second,R=Pos[r];
		for(LL x=1;x<R;x++) Add[x]+=A[r];
		for(LL x=R+1;x<=cnt;x++) t[x]++;
		for(LL x=St[R];x<r;x++) B[x]+=A[r];
		for(LL x=r+1;x<=Ed[R];x++) B[x]+=A[x];
		B[r]=-INF;
		Build(R); 
	}
	cout<<Ans;
} 
posted @ 2021-12-29 10:37  Larunatrecy  阅读(33)  评论(0)    收藏  举报