洛谷P5504 [JSOI2011]柠檬
题意简述
给你一个长度为 \(n(n\leq 10^5)\) 的序列,将其分成若干段,每段选择一个数,获得这个数的价值 \(\times\) 它在这段出现次数的平方,求最大总价值。
做法
引理:对于任意一个 \(i\),所选的最后一段所指定的 \(s_0\) 定为 \(s_i\)。
证明:\(i\) 这个点会在 \(s_0 \not =s_i\) 没有贡献,不如最后一段只选 \(i\)。
所以考虑动态规划,令 \(f_i\) 为以 \(i\) 结尾的最大值,\(c_i\) 为出现次数的前缀和,可以得到如下转移方程:
\[f_i=\max_{j\leq i \wedge s_i=s_j} \{f_{j-1}+s_i(c_i-c_{j}+1)^2\}
\]
暴力求解是 \(O\left(n^2\right)\) 的,发现 dp 方程中存在积的形式,考虑斜率优化可得:
\[f_i-s_i{c_i}^2=\max_{j\leq i \wedge s_i=s_j} \{f_{j-1}+s_i(c_{j}+1)^2-s_ic_i\times 2(c_j-1)\}
\]
令 \(y=f_i-s_i{c_i}^2\),\(k=-s_ic_i\),\(x=2(c_j-1)\),\(b=f_{j-1}+s_i(c_{j}+1)^2\),可得:
\[y=\max_{j\leq i \wedge s_i=s_j} \{kx+b\}
\]
此处 \(k\),\(x\) 单调递增,维护上凸壳二分查询即可。时间复杂度 \(O(n\log n)\)。
Code
之前二分写成了 r=mid-1 调了半个多小时,我酸了....
#pragma GCC optimize(2,3,"Ofast","unroll-loops")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register int
#define db double
#define in inline
namespace fast_io
{
char buf[1<<12],*p1=buf,*p2=buf,sr[1<<23],z[23],nc;int C=-1,Z=0,Bi=0;
in char gc() {return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;}
in ll read()
{
ll x=0,y=1;while(nc=gc(),(nc<48||nc>57)&&nc!=-1)if(nc==45)y=-1;Bi=1;
x=nc-48;while(nc=gc(),47<nc&&nc<58)x=(x<<3)+(x<<1)+(nc^48),Bi++;return x*y;
}
in db gf() {re a=read(),b=(nc!='.')?0:read();return (b?a+(db)b/pow(10,Bi):a);}
in int gs(char *s) {char c,*t=s;while(c=gc(),c<32);*s++=c;while(c=gc(),c>32)*s++=c;return s-t;}
in void ot() {fwrite(sr,1,C+1,stdout);C=-1;}
in void flush() {if(C>1<<22) ot();}
template <typename T>
in void write(T x,char t)
{
re y=0;if(x<0)y=1,x=-x;while(z[++Z]=x%10+48,x/=10);
if(y)z[++Z]='-';while(sr[++C]=z[Z],--Z);sr[++C]=t;flush();
}
in void write(char *s) {re l=strlen(s);for(re i=0;i<l;i++)sr[++C]=*s++;sr[++C]='\n';flush();}
};
using namespace fast_io;
const int N=1e5+5,M=1e4+5;
#define q v[a[i]]
#define push push_back
#define pop pop_back
int n,a[N],cnt[M],c[N];
ll f[N];
vector<int>v[N];
in ll sqr(ll x) {return x*x;}
in ll slp(re i,re j,re k)
{
ll xi=2*c[i],bi=f[i-1]+a[i]*sqr(c[i]);
ll xj=2*c[j],bj=f[j-1]+a[j]*sqr(c[j]),xk=2*c[k],bk=f[k-1]+a[k]*sqr(c[k]);
return ((xi-xj)*(bk-bj)-(bi-bj)*(xk-xj))>0;
}
in ll calc(re i,re x) {return f[x-1]+a[i]*sqr(c[i]-c[x]+1);}
int main()
{
n=read();
for(re i=1,l,r,mid,t;i<=n;i++)
{
a[i]=read(),c[i]=(++cnt[a[i]])-1;
while((t=q.size()-1)>0&&slp(i,q[t],q[t-1])) q.pop();q.push(i);
for(l=0,r=q.size();mid=(l+r)>>1,l+1<r;) (calc(i,q[mid])>calc(i,q[mid-1]))?l=mid:r=mid;
f[i]=calc(i,q[l]);
}
write(f[n],'\n');
return ot(),0;
}
//Author: disangan233
//In my dream's scene,I can see the everything that in Cyaegha.

浙公网安备 33010602011771号