zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 833 字符串中的查找与替换(暴力模拟)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 832 翻转图像(位运算)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    Java实现 LeetCode 831 隐藏个人信息(暴力)
    how to use automapper in c#, from cf~
  • 原文地址:https://www.cnblogs.com/gmh77/p/13731847.html
Copyright © 2011-2022 走看看