zoukankan      html  css  js  c++  java
  • CF573E Bear and Bowling

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

  • 相关阅读:
    springboot的jar为何能独立运行
    掌握SpringBoot-2.3的容器探针:实战篇
    掌握SpringBoot-2.3的容器探针:深入篇
    掌握SpringBoot-2.3的容器探针:基础篇
    详解SpringBoot(2.3)应用制作Docker镜像(官方方案)
    体验SpringBoot(2.3)应用制作Docker镜像(官方方案)
    kubespray2.11安装kubernetes1.15
    Jenkins集群下的pipeline实战
    快速搭建Jenkins集群
    前端开发神器Charles从入门到卸载
  • 原文地址:https://www.cnblogs.com/Troverld/p/14611517.html
Copyright © 2011-2022 走看看