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\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-09-25 18:59  gmh77  阅读(184)  评论(0编辑  收藏  举报