码迷,mamicode.com
首页 > 其他好文 > 详细

CF573E Bear and Bowling

时间:2021-04-05 11:56:10      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:长度   https   can   一段   com   pushd   元素   int   print   

XXVII.CF573E Bear and Bowling

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

考虑由 \(f_i\) 转移到 \(f_{i+1}\)。明显,一共有两种转移方式:\(f_{i,j}\rightarrow f_{i+1,j}\),或 \(f_{i,j}+(j+1)a_{i+1}\rightarrow f_{i+1,j+1}\)

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

总复杂度 \(O(n\log^2n)\)

代码:

#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;
}

CF573E Bear and Bowling

标签:长度   https   can   一段   com   pushd   元素   int   print   

原文地址:https://www.cnblogs.com/Troverld/p/14611517.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!