传送门ber~
容易发现选的每一段左右一定是同色…
那么有
fi=max{fj−1+(si−sj+1)2∗ai}
f
i
=
m
a
x
{
f
j
−
1
+
(
s
i
−
s
j
+
1
)
2
∗
a
i
}
其中
i
i
,同色
若存在
k>t
k
>
t
且答案更优,即
y=fk−1+ps2k−2psk y = f k − 1 + p s k 2 − 2 p s k
x=2psk x = 2 p s k
fk−1+ps2i+ps2k+p−2psisk−2psk+2psi f k − 1 + p s i 2 + p s k 2 + p − 2 p s i s k − 2 p s k + 2 p s i
=y−xsi+ps2i+p+2psi = y − x s i + p s i 2 + p + 2 p s i
斜率优化
单调栈
代码如下·:
#include<algorithm>
#include<cstring>
#include<ctype.h>
#include<cstdio>
#include<vector>
#define int long long
#define INF 2147483647
#define N 100020
using namespace std;
inline int read(){
int x=0,f=1;char c;
do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
typedef long long LL;
struct Data{
LL x,y;
Data(){}
Data(LL x,LL y):x(x),y(y){}
}tmp;
vector<Data>s[N];
int n,x,y,p,ans;
int cnt[N],pos[N],a[N],pre[N],top[N],f[N];
inline double Slope(Data a,Data b){
if(a.x==b.x) return a.y>b.y?-INF:INF;
return 1.0*(b.y-a.y)/(b.x-a.x);
}
main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
pre[i]=pos[a[i]];
pos[a[i]]=i;
cnt[i]=cnt[pre[i]]+1;
}
memset(pos,0,sizeof pos);
for(int i=1;i<=n;++i)
if(!pos[a[i]])
s[a[i]].push_back(Data(0,0)),pos[a[i]]=1;
for(int i=1;i<=n;i++){
p=a[i];
tmp=Data(2*p*cnt[i],f[i-1]+p*cnt[i]*cnt[i]-2*p*cnt[i]);
while(top[p]>1 && Slope(s[p][top[p]-1],s[p][top[p]])<=Slope(s[p][top[p]],tmp)) top[p]--,s[p].pop_back();
top[p]++;s[p].push_back(tmp);
while(top[p]>1 && Slope(s[p][top[p]-1],s[p][top[p]])<=cnt[i]) top[p]--,s[p].pop_back();
x=s[p][top[p]].x;y=s[p][top[p]].y;
f[i]=y-x*cnt[i]+p*cnt[i]*cnt[i]+p+2*p*cnt[i];
ans=max(ans,f[i]);
}
printf("%lld",ans);
return 0;
}

本文详细解析了使用斜率优化技巧解决动态规划问题的方法,并通过一个具体的实例来展示如何运用单调栈实现高效的斜率优化算法。

695

被折叠的 条评论
为什么被折叠?



