分析
那么朴素的dp方程设
d
p
[
i
]
[
k
]
dp[i][k]
dp[i][k]表示前
i
i
i个数分割
k
k
k次的最大得分
d
p
[
i
]
[
k
]
=
max
{
d
p
[
j
]
[
k
−
1
]
+
s
u
m
j
∗
(
s
u
m
i
−
s
u
m
j
)
}
dp[i][k]=\max \{dp[j][k-1]+sum_j*(sum_i-sum_j)\}
dp[i][k]=max{dp[j][k−1]+sumj∗(sumi−sumj)}
首先第二维可以滚掉,所以等同于
d
p
[
i
]
=
max
{
d
p
[
j
]
+
s
u
m
j
∗
(
s
u
m
i
−
s
u
m
j
)
}
dp[i]=\max\{dp[j]+sum_j*(sum_i-sum_j)\}
dp[i]=max{dp[j]+sumj∗(sumi−sumj)}
设
k
(
j
<
k
)
k(j<k)
k(j<k)更优于
j
j
j,那么
d
p
[
j
]
+
s
u
m
j
∗
(
s
u
m
i
−
s
u
m
j
)
≤
d
p
[
k
]
+
s
u
m
k
∗
(
s
u
m
i
−
s
u
m
k
)
dp[j]+sum_j*(sum_i-sum_j)\leq dp[k]+sum_k*(sum_i-sum_k)
dp[j]+sumj∗(sumi−sumj)≤dp[k]+sumk∗(sumi−sumk)
化简得到
d
p
[
j
]
−
d
p
[
k
]
−
s
u
m
j
2
+
s
u
m
k
2
≤
(
s
u
m
k
−
s
u
m
j
)
s
u
m
i
dp[j]-dp[k]-sum_j^2+sum_k^2\leq (sum_k-sum_j)sum_i
dp[j]−dp[k]−sumj2+sumk2≤(sumk−sumj)sumi
那么
(
d
p
[
j
]
−
s
u
m
j
2
)
−
(
d
p
[
k
]
−
s
u
m
k
2
)
s
u
m
k
−
s
u
m
j
≤
s
u
m
i
\frac{(dp[j]-sum_j^2)-(dp[k]-sum_k^2)}{sum_k-sum_j}\leq sum_i
sumk−sumj(dp[j]−sumj2)−(dp[k]−sumk2)≤sumi
可以知道
s
u
m
i
sum_i
sumi单调递增,所以维护下凸壳
然后你就WA了,因为要输出方案,而且
d
p
dp
dp方程是两个数组交替滚动
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
long long f[100001],dp[100001];
int n,k,sum[100001],q[100001],pre[100001][211];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline long long sq(int x){return 1ll*sum[x]*sum[x]-dp[x];}
inline double slope(int j,int k){
return sum[k]==sum[j]?-1e10:(1.0*(sq(k)-sq(j))/(sum[k]-sum[j]));
}
inline void dfs(int m,int k){
if (pre[m][k]) dfs(pre[m][k],k-1),printf("%d ",pre[m][k]);
}
signed main(){
n=iut(); k=iut();
for (rr int i=1;i<=n;++i) sum[i]=sum[i-1]+iut();
for (rr int j=1;j<=k;++j){
rr int head=1,tail=0; q[++tail]=0;
for (rr int i=1;i<=n;++i){
while (head<tail&&slope(q[head],q[head+1])<=sum[i]) ++head;
f[i]=dp[q[head]]+1ll*sum[q[head]]*(sum[i]-sum[q[head]]),pre[i][j]=q[head];
while (head<tail&&slope(q[tail-1],q[tail])>slope(q[tail],i)) --tail;
q[++tail]=i;
}
memcpy(dp,f,sizeof(dp));
}
printf("%lld\n",f[n]);
dfs(n,k);
return 0;
}