题目大意
题解
结论:一个长度为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;
}