题目描述:
样例:
input1:
5
-2 -8 0 5 -3
output1:
5 10 13 2 -13
input2:
6
-10 20 -30 40 -50 60
output2:
60 160 280 390 400 210
数据范围与约定:
考虑DP:令\(dp(i,j)\)表示前\(i\)个点选\(j\)个,能得到的最大价值。
得到转移方程:\(dp(i,j)=\max\{dp(i-1,j),dp(i-1,j-1)+a_i\cdot j\}\)
这个方程很明显是\(n^2\)的。
经过打表/分析样例/严谨证明(不可能的),可以发现结论:\(i\)相同时,转移方程中满足后一种决策
更优的\(j\)一定是一段后缀 。
(人话:只要求\(dp(i,j_0)\)时选了\(a_i\),那么对于所有\(j\geq j_0\),都会选择\(a_i\))
证明嘛,我看不懂,就直接复制上来啦
考虑选择后一个决策的条件:\(dp(i-1,j-1)+a_i\cdot j \geq dp(i-1,j)\),即\(a_i\cdot j\geq dp(i-1,j)-dp(i-1,j-1)\)。
于是我们可以用一棵平衡树来维护\(dp(i-1,j)-dp(i-1,j-1)?\)(即它的差分),在上面二分出\(j_0?\)后就可以插入这个位置并对后缀进行区间加了(本来是区间加上一个等差序列,但这里已经差分过了,就可以普通区间加了)。
复杂度\(O(n\log n)\),代码很短。
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define mod 998244353
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 200010
typedef long long ll;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar();
if(ch==‘.‘)
{
ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file(){freopen("a.txt","r",stdin);}
inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
namespace Splay
{
ll w[sz],tag[sz];
int fa[sz],ch[sz][2],size[sz],root,cnt;
#define ls ch[x][0]
#define rs ch[x][1]
void Add(int x,ll t){w[x]+=t;tag[x]+=t;}
void pushdown(int x){ ll &t=tag[x]; if (t) { Add(ls,t); Add(rs,t); } t=0; }
void pushup(int x){size[x]=size[ls]+size[rs]+1;}
bool get(int x){return ch[fa[x]][1]==x;}
void rotate(int x)
{
int y=fa[x],z=fa[y],k=get(x),w=ch[x][!k];
if (z) pushdown(z);pushdown(y);pushdown(x);
if (z) ch[z][get(y)]=x;ch[x][!k]=y;ch[y][k]=w;
if (w) fa[w]=y;fa[y]=x;fa[x]=z;
pushup(y);pushup(x);
}
void splay(int x)
{
while (fa[x])
{
int y=fa[x];
if (fa[y]) rotate(get(x)==get(y)?y:x);
rotate(x);
}
root=x;
}
void insert(int &x,int f,ll cur,ll v)
{
if (!x)
{
x=++cnt;
fa[x]=f;size[x]=1;w[x]=(cur+1)*v;
return splay(x);
}
pushdown(x);
int siz=cur+1+size[ls];
if (w[x]>=v*siz) insert(rs,x,siz,v);
else insert(ls,x,cur,v);
}
void getans(int x,ll &cur)
{
pushdown(x);
if (ls) getans(ls,cur);
printf("%lld ",cur+=w[x]);
if (rs) getans(rs,cur);
}
#undef ls
#undef rs
}
using namespace Splay;
int n;
ll a[sz];
int main()
{
file();
read(n);
rep(i,1,n) read(a[i]);
rep(i,1,n)
{
insert(root,0,0,a[i]);
if (ch[root][1]) Add(ch[root][1],a[i]);
}
ll ans=0;
getans(root,ans);
}
原文地址:https://www.cnblogs.com/p-b-p-b/p/10261047.html
时间: 2024-10-08 13:29:55