• CF573E.Bear and Bowling


    题目大意

    题解

    结论:一个长度为x的最优解一定是x-1加上当前加上后贡献最大的数

    证明:

    设x-1集合为S,假设加上一个数x,并且x不在最终的集合里面

    设最终是S+S2,把S2中最小于x中最大的x的那个拿出来,设为y

    一个数的贡献可以写作ai*k+bi,如果存在i<j且ai>aj那么显然i必选

    因为选了x且y<x,所以满足ay<=ax

    那么在之后的操作中,如果在y前面加了一个数则对x的贡献更大,在x后面加则一样,因此直到最后x都会比y优,因此选了y的话肯定会选x

    如果x是最小的那个也同理

    那么可以分块维护,O(n√n)

    根据这个结论可以得到另一个结论:一个数有一个加入时间k,当长度>=k时一定加,否则一定不加

    因此可以优化n^2dp,用平衡树维护f[i]-f[i-1],需要支持插入以及区间加ai,二分直接在平衡树上二分分界点,化一下式子发现只需要判断当前点的值

    时间O(nlogn)

    话说好像有很多人是水过去的

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define max(a,b) (a>b?a:b)
    #define ll long long
    //#define file
    using namespace std;
    
    int fa[100011],sum[100011],n,i,j,k,l,len,rt;
    ll a[100001],tr[100011][3],Tr[100011],s,ans,Ans;
    
    void New(int t,int x) {tr[t][x]=++len;fa[len]=t;sum[len]=1;}
    void down(int t)
    {
    	if (t && Tr[t])
    	{
    		tr[t][2]+=Tr[t];
    		if (tr[t][0]) Tr[tr[t][0]]+=Tr[t];
    		if (tr[t][1]) Tr[tr[t][1]]+=Tr[t];
    		Tr[t]=0;
    	}
    }
    void up(int t) {sum[t]=sum[tr[t][0]]+sum[tr[t][1]]+1;}
    void rot(int t)
    {
    	if (!t) return;
    	int Fa=fa[t],Fa2=fa[Fa],x=tr[Fa][1]==t,x2=tr[Fa2][1]==Fa,son=tr[t][x^1];
    	down(Fa),down(t);
    	
    	tr[t][x^1]=Fa,fa[son]=Fa;
    	fa[t]=Fa2,tr[Fa][x]=son;
    	fa[Fa]=t;if (Fa2) tr[Fa2][x2]=t;
    	up(Fa),up(t);
    	if (rt==Fa) rt=t;
    }
    void splay(int t)
    {
    	int Fa,Fa2;
    	
    	down(t);
    	while (rt!=t)
    	{
    		Fa=fa[t],Fa2=fa[Fa];
    		if (rt!=Fa)
    		{
    			if ((tr[Fa2][0]==Fa)^(tr[Fa][0]==t))
    			rot(t),rot(t);
    			else
    			rot(Fa),rot(t);
    		}
    		else rot(t);
    	}
    }
    int find(ll a)
    {
    	int i,j,k,l,t=rt,ans=0,ls;
    	ll s=0;
    	
    	if (::i==4)
    	n=n;
    	
    	while (t)
    	{
    		ls=t,down(t);
    		if (t!=1 && tr[t][2]<=(s+sum[tr[t][0]])*a) ans=(t>1)?t:ans,t=tr[t][0];
    		else s+=sum[tr[t][0]]+1,t=tr[t][1];
    	}
    	splay(ls);
    	return ans;
    }
    void dfs(int t)
    {
    	down(t);
    	if (tr[t][0]) dfs(tr[t][0]);
    	Ans+=tr[t][2],ans=max(ans,Ans);
    	if (tr[t][1]) dfs(tr[t][1]);
    }
    
    int main()
    {
    	#ifdef file
    	freopen("CF573E.in","r",stdin);
    //	freopen("a.out","w",stdout);
    	#endif
    	
    	scanf("%d",&n);
    	fo(i,1,n) scanf("%lld",&a[i]);
    	
    	len=rt=1;tr[1][2]=0;sum[1]=1;
    	fo(i,1,n)
    	{
    		if (i==4)
    		n=n;
    		
    		l=find(a[i]);
    		if (!l)
    		{
    			j=rt,s=0;
    			while (tr[j][1])
    			down(j),s+=sum[tr[j][0]]+1,++sum[j],j=tr[j][1];
    			down(j),s+=sum[tr[j][0]]+1,New(j,1),++sum[j];
    			tr[len][2]=s*a[i],splay(len);
    		}
    		else
    		{
    			splay(l),s=0;
    			j=tr[l][0];
    			while (tr[j][1])
    			down(j),j=tr[j][1];
    			down(j),splay(j),Tr[l]+=a[i],down(l);
    			New(l,0),++sum[l],++sum[j];
    			tr[len][2]=1ll*(sum[tr[j][0]]+1)*a[i];
    			splay(len);
    		}
    	}
    	
    	dfs(rt);
    	printf("%lld
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    C++ const用于iterator
    C++实现类似python中的字符串split函数
    简单地解释overwrite
    ubuntu16.04 新安装的系统启动ssh服务
    强化学习7日打卡营-世界冠军带你从零实践--基于表格型方法的 RL
    spark-遇到问题小结
    Spark 读写hive 表
    spark-shell 显示乱码
    机器学习-GBDT和XGboost
    链表
  • 原文地址:https://www.cnblogs.com/gmh77/p/13731847.html
Copyright © 2020-2023  润新知