题面描述
思路
对于同一种分割方式,顺序不会影响最终结果。
分析样例 ( 4 , 1 , 3 , 4 , 0 , 2 , 3 ) (4,1,3,4,0,2,3) (4,1,3,4,0,2,3),
如果先切 5 5 5,则 ( 4 + 1 + 3 + 4 + 0 ) ∗ ( 2 + 3 ) = 60 (4+1+3+4+0)*(2+3)=60 (4+1+3+4+0)∗(2+3)=60
再切 3 3 3,则 ( 4 + 1 + 3 ) ∗ ( 4 + 0 ) = 32 (4+1+3)*(4+0)=32 (4+1+3)∗(4+0)=32
最后切 1 1 1,则 4 ∗ ( 1 + 3 ) = 16 4*(1+3)=16 4∗(1+3)=16
结果 60 + 32 + 16 = 108 60+32+16=108 60+32+16=108
通过玄学研究观察,我们发现最后分成块的元素:
- 一定不会与同块的元素相乘对答案产生贡献
(因为只有分块时,才会进行操作,对答案产生贡献) - 会与其他块的所有元素进行相乘且仅乘一次,对答案产生贡献
那么我们就可以判断:
对于同一种分割方式,顺序不会影响最终结果.
因此仅有切的位置会影响结果
所以这是我们可以推出状态转移方程
设 s s s为 a a a的前缀和
F i , p + 1 = max ( F j , p + s j ∗ ( s i − s j ) ) F_{i,p+1}=\max(F_{j,p}+s_j*(s_i-s_j)) Fi,p+1=max(Fj,p+sj∗(si−sj))
决策单调性
设
F k , p + s k ∗ ( s i − s k ) ≥ F j , p + s j ∗ ( s i − s j ) ( j < k < i ) F_{k,p}+s_k*(s_i-s_k)\ge F_{j,p}+s_j*(s_i-s_j)(j<k<i) Fk,p+sk∗(si−sk)≥Fj,p+sj∗(si−sj)(j<k<i)
正好符合
- 一定不会与同块的元素相乘对答案产生贡献
(因为只有分块时,才会进行操作,对答案产生贡献) - 会与其他块的所有元素进行相乘且仅乘一次,对答案产生贡献
在未来状态 t t t下,
证明:
F k , p + s k ∗ ( s t − s k ) ≥ F j , p + s j ∗ ( s t − s j ) F_{k,p}+s_k*(s_t-s_k)\ge F_{j,p}+s_j*(s_t-s_j) Fk,p+sk∗(st−sk)≥Fj,p+sj∗(st−sj)
由于 s t = s i + v a l s_t=s_i+val st=si+val,
F k , p + s k ∗ ( s i + v a l − s k ) ≥ F j , p + s j ∗ ( s i + v a l − s j ) F_{k,p}+s_k*(s_i+val-s_k)\ge F_{j,p}+s_j*(s_i+val-s_j) Fk,p+sk∗(si+val−sk)≥Fj,p+sj∗(si+val−sj)
只需证明:
s k ∗ v a l ≥ s j ∗ v a l s_k*val\ge s_j*val sk∗val≥sj∗val
由于 v a l > 0 , s k ≥ s j val>0,s_k\ge s_j val>0,sk≥sj
证毕。
注意,为了保证单调性,我们要避免 s k = = s j s_k== s_j sk==sj,避免出锅
踢队头
F k , p + s k ∗ ( s i − s k ) ≥ F j , p + s j ∗ ( s i − s j ) ( j < k < i ) F_{k,p}+s_k*(s_i-s_k)\ge F_{j,p}+s_j*(s_i-s_j)(j<k<i) Fk,p+sk∗(si−sk)≥Fj,p+sj∗(si−sj)(j<k<i)
F k , p + s k ∗ ( s i − s k ) ≥ F j , p + s j ∗ ( s i − s j ) F_{k,p}+s_k*(s_i-s_k)\ge F_{j,p}+s_j*(s_i-s_j) Fk,p+sk∗(si−sk)≥Fj,p+sj∗(si−sj)
F j , p − F k , p − s j 2 + s k 2 ≤ s i ∗ ( s k − s j ) F_{j,p}-F_{k,p}-{s_j}^2+{s_k}^2\le s_i*(s_k-s_j) Fj,p−Fk,p−sj2+sk2≤si∗(sk−sj)
由于 s k − s j > 0 s_k-s_j>0 sk−sj>0,
c a l c ( j , k ) = F j , p − F k , p − s j 2 + s k 2 s k − s j ≤ s i calc(j,k)=\frac{F_{j,p}-F_{k,p}-{s_j}^2+{s_k}^2}{s_k-s_j}\le s_i calc(j,k)=sk−sjFj,p−Fk,p−sj2+sk2≤si
当 c a l c ( j , k ) ≤ s i calc(j,k)\le s_i calc(j,k)≤si时, k k k优于 j j j.
因此当 c a l c ( q h e a d , q h e a d + 1 ) ≤ s i calc(q_{head},q_{head+1})\le s_i calc(qhead,qhead+1)≤si
h e a d + 1 head+1 head+1优于 h e a d head head。
由于 s i s_i si随 i i i增大而增大,那么 c a l c ( q h e a d , q h e a d + 1 ) calc(q_{head},q_{head+1}) calc(qhead,qhead+1)随 h e a d head head增大而增大,才符合 h e a d head head为最优解,因此斜率是不断递增的,要维护一个下凸壳。
踢队尾
根据斜率是不断递增的,仅当
c a l c ( q t a i l , i ) ≥ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\ge calc(q_{tail-1},q_{tail}) calc(qtail,i)≥calc(qtail−1,qtail)
斜率才满足不断递增。
故当
c a l c ( q t a i l , i ) ≤ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\le calc(q_{tail-1},q_{tail}) calc(qtail,i)≤calc(qtail−1,qtail)
删去队尾。
AC code
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define ll long long
#define gc getchar()
using namespace std;
const int N=1e5+10;
inline void qr(ll &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
inline void qw(ll x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
ll f[N],g[N],s[N];
int q[N],l,r,pre[N][210];
inline double calc(int j,int k)
{
if(s[k]==s[j]) return -1e18;
return (double)(g[j]-g[k]-s[j]*s[j]+s[k]*s[k])/(s[k]-s[j]);
}
int main()
{
int n,k;scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
qr(s[i]);s[i]+=s[i-1];
}
int tot=0;
for(int i=1;i<=k;i++)
{
l=1;r=1;q[1]=0;memcpy(g,f,sizeof(g));
for(int j=1;j<=n;j++)
{
while(l<r&&calc(q[l],q[l+1])<=(double)s[j])++l;
f[j]=g[q[l]]+s[q[l]]*(s[j]-s[q[l]]);
pre[j][i]=q[l];
while(l<r&&calc(j,q[r])<=calc(q[r-1],q[r]))--r;
q[++r]=j;
}
}
qw(f[n]);puts("");
int j=n,i=k;
while(pre[j][i])printf("%d ",pre[j][i]),j=pre[j][i],--i;
return 0;
}