CF573E Bear and Bowling

XXVII.CF573E Bear and Bowling

考虑暴力的DP。设 fi,j 表示前 i 个元素中选择长度为 j 的子序列所能得到的最大收益。

考虑由 fi 转移到 fi+1。明显,一共有两种转移方式:fi,jfi+1,j,或 fi,j+(j+1)ai+1fi+1,j+1

大胆猜测,采取转移一的,一定是 fi 上一段前缀(可以用暴力莽一下试试看)。于是我们全程采取一棵平衡树维护每个 fi 数组。当进行转移的时候,二分求出上述分界点(这里不能使用平衡树上二分,因为需要同时检查相邻两个数的值)。然后就是单点插入、区间等差数列加了,都是基础操作。

总复杂度 O(nlog2n)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll res;
int n,a[100100],rt,cnt;
struct Treap{
	int ch[2],sz,rd;
	ll val,tag,dif;
}t[100100];
#define lson t[x].ch[0]
#define rson t[x].ch[1]
void pushup(int x){t[x].sz=t[lson].sz+t[rson].sz+1;}
void ADD(int x,ll val,ll dif){t[x].val+=val,t[x].tag+=val,t[x].dif+=dif;}
void pushdown(int x){
	if(lson)ADD(lson,t[x].tag-t[x].dif*(t[t[lson].ch[1]].sz+1),t[x].dif);
	if(rson)ADD(rson,t[x].tag+t[x].dif*(t[t[rson].ch[0]].sz+1),t[x].dif);
	t[x].dif=t[x].tag=0;
}
int merge(int x,int y){
	if(!x||!y)return x+y;
	if(t[x].rd>t[y].rd){pushdown(x),t[x].ch[1]=merge(t[x].ch[1],y),pushup(x);return x;}
	else{pushdown(y),t[y].ch[0]=merge(x,t[y].ch[0]),pushup(y);return y;}
}
void split(int x,int k,int &u,int &v){
	if(!x){u=v=0;return;}
	pushdown(x);
	if(t[lson].sz>=k)v=x,split(lson,k,u,lson);
	else u=x,split(rson,k-t[lson].sz-1,rson,v);
	pushup(x);
}
ll kth(int k){
	if(!k)return 0;
	int a,b,c;
	split(rt,k-1,a,b);
	split(b,1,b,c);
	ll ret=t[b].val;
	rt=merge(merge(a,b),c);
	return ret;
}
void Insert(int k,ll y){//insert an element and let it be the k-th one
	int a,b;
	split(rt,k-1,a,b);
	int x=++cnt;
	t[x].val=y,t[x].rd=rand()*rand();
	rt=merge(merge(a,x),b);
}
void Add(int k,int y){
	int a,b;
	split(rt,k-1,a,b);
	t[b].val+=1ll*(k+t[t[b].ch[0]].sz)*y;
	t[b].tag+=1ll*(k+t[t[b].ch[0]].sz)*y;
	t[b].dif+=y;
	rt=merge(a,b);
}
void Iterate(int x){
	if(!x)return;
	pushdown(x),Iterate(lson),Iterate(rson);
	res=max(res,t[x].val);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++){
		int l=1,r=i;
		while(l<r){
			int mid=(l+r)>>1;
			if(kth(mid-1)+1ll*a[i]*mid>=kth(mid))r=mid;
			else l=mid+1;
		}
		Insert(r,kth(r-1));
		Add(r,a[i]);
	}
	Iterate(rt);
	printf("%lld\n",res);
	return 0;
}

posted @   Troverld  阅读(74)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示