zoukankan      html  css  js  c++  java
  • 【CF573E】Bear and Bowling(分块维护凸壳)

    点此看题面

    • 给定一个序列(a_{1sim n}),要求从中选出一个子序列(b_{1sim m}),最大化(sum_{i=1}^mi imes b_i)
    • (nle10^5,|a_i|le10^7)

    贪心

    一个贪心,就是我们每次选取贡献最大的位置尝试加入。

    这个贪心正确性显然,因此问题就在于怎么表示贡献并求出最大值。

    分块维护凸壳

    这里的贡献要分两类讨论,设其为(a_i imes t+b),其中(t)为之前选中的数个数(+1)(b)为之后所有选中的数之和。

    选取了一个数,相当于要给之前全部的(b)加上(a_i),给之后所有的(t)加上(1)

    一般的数据结构似乎都不擅长维护这种东西,发现这里的(t)是单调递增的,因此考虑分块,并对每个块维护一个凸壳搞斜率优化。

    对于一个块,我们先将所有元素按照斜率(a_i)排个序,然后维护一个凸壳。

    要给一个块(b)全部加上(a_i),显然不会对块内元素之间的相对大小关系造成任何影响,只要打标记即可。

    要给一个块(t)全部加上(1),同样打上一个标记,然后在询问一个块的答案时,首先把开头不优的元素弹出,再返回开头元素(经典斜率优化操作)。

    至于最优元素所在块,我们只需把它的贡献修改为(-INF),暴力改完前后的贡献,然后重构这个块的凸壳即可。

    代码:(O(nsqrt n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define BT 320
    #define BS 320
    #define LL long long
    #define Pr pair<LL,int>
    using namespace std;
    int n,sz,a[N+5],bl[N+5];LL f[N+5];I bool cmp(CI x,CI y) {return a[x]<a[y];}
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define D isdigit(oc=tc())
    	int Ff;char oc,FI[FS],*FA=FI,*FB=FI;
    	Tp I void read(Ty& x) {x=0,Ff=1;W(!D) Ff=oc^'-'?1:-1;W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));x*=Ff;}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }using namespace FastIO;
    struct Block
    {
    	#define V(x) (f[x]+a[x]*t+b)//算上标记计算实际值
    	int H,T,q[BS+5],p[BS+5];LL t,b;
    	I void Build(CI L,CI R)//建块
    	{
    		RI i;for(i=L;i<=R;++i) f[p[i-L+1]=i]+=a[i]*t+b;t=b=0;sort(p+1,p+R-L+2,cmp);//按斜率排序
    		#define S(x,y) (a[x]^a[y]?1.0*(f[y]-f[x])/(a[y]-a[x]):(f[y]>f[x]?1e18:-1e18))
    		for(H=1,T=0,i=1;i<=R-L+1;q[++T]=p[i++]) W(H<T&&S(q[T-1],q[T])<S(q[T],p[i])) --T;//维护凸壳
    	}
    	I Pr Q() {W(H<T&&V(q[H])<V(q[H+1])) ++H;return make_pair(V(q[H]),q[H]);}//弹去队首不优元素
    }B[BT+5];
    int main()
    {
    	RI i,x;for(read(n),sz=sqrt(n),i=1;i<=n;++i) read(a[i]),bl[i]=(i-1)/sz+1,f[i]=a[i];
    	for(i=1;i<=bl[n];++i) B[i].Build((i-1)*sz+1,min(i*sz,n));//初始建块
    	Pr k;LL ans=0;W(true)
    	{
    		for(k=make_pair(0LL,0),i=1;i<=bl[n];++i) k=max(k,B[i].Q());if(!k.first) break;ans+=k.first,x=k.second;//直至没有贡献
    		for(i=1;i^bl[x];++i) B[i].b+=a[x];for(i=bl[x]+1;i<=bl[n];++i) ++B[i].t;//更新前后块
    		for(i=(bl[x]-1)*sz+1;i^x;++i) f[i]+=a[x];for(i=x+1;i<=min(bl[x]*sz,n);++i) f[i]+=a[i];//更新当前块前后元素
    		f[x]=-1e18,B[bl[x]].Build((bl[x]-1)*sz+1,min(bl[x]*sz,n));//把当前位置贡献改为-INF,重构当前块
    	}return printf("%lld
    ",ans),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    ubuntu :安装skype聊天工具
    ubuntu :安装一个方便的终端工具,Guake Terminal
    ubuntu :安装好了搜狗输入法但是没法用
    Qt学习笔记(1) hello world
    Sublime + python2.7 + opencv (轻量级开发环境)
    Clion + opencv环境搭建(体验最好的C++ IDE)
    最快入门程序员
    isinstance,issubclass
    类的封装,property特性,类与对象的绑定方法和非绑定方法,
    类的继承,派生,组合,菱形继承问题,类的多态和多态性
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF573E.html
Copyright © 2011-2022 走看看