在一条直线上,有n个火车站,第i条铁轨连接着第i个和第i+1个火车站。
每个火车站都有一个花费wi。
定义所有火车站的总花费为∑i和j可以互相到达wiwj。
比如有4个火车站,权值分别为4,5,1,2。
如图:4 — 5 — 1 — 2,总花费为:4*5 + 4*1 + 4*2 + 5*1 + 5*2 + 1*2 = 49
现在给你机会去炸掉m条铁轨,希望你能让火车站的总花费最小。
假设m=1,你可以炸掉5 — 1这条铁轨,变成了这样: 4 — 5 -X- 1 — 2,总花费为4*5 + 1*2 = 22。
但是你炸4 — 5这条更优,因为总花费变成了5*1 + 5*2 + 1*2 = 17。
输入格式:
第一行,两个整数n,m(0≤m
%:pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define N 2001
#define r(x) scanf("%d",&x)
#define pln(x) printf("%d\n",x)
#define pk(x) printf("%d ",x)
#define p(x) printf("%d",x)
#define PER(i,a,b) for(int i=a;i<=b;i++)
#define REP(i,a,b) for(int i=a;i>=b;i--)
int n,m;
long long dp[N][N];
long long a[N];
long long S[N];
long long sq[N];
long long d[N][N];
long long G[N][N];
int q[N+2],h,t;
long long up(int x,int y,int kk)
{
return (dp[x][kk-1]-dp[y][kk-1])+S[x]*S[x]-S[y]*S[y];
}
long long down(int x,int y,int kk)
{
return 2*(S[x]-S[y]);
}
//long long getdp(int x,int y,int xx){return dp[xx][y]+G[xx+1][x];}
int main()
{
r(n);r(m);
PER(i,1,n) r(a[i]);
PER(i,1,n) sq[i]=sq[i-1]+a[i]*a[i];
PER(i,1,n) S[i]=S[i-1]+a[i];
// PER(i,1,n) cout<<S[i]<<" ";
PER(i,1,n) PER(k,1,i) G[k][i]=(S[i]-S[k-1])*(S[i]-S[k-1]);
PER(i,1,n) dp[i][0]=G[1][i];
PER(j,1,m)
{
memset(q,0,sizeof(q));
h=t=0;
// h=1
q[++t]=0;
PER(i,1,n)
{
while(h<t&&up(q[h+1],q[h],j)<=S[i]*down(q[h+1],q[h],j)) h++;
dp[i][j]=dp[q[h]][j-1]+(S[i]-S[q[h]])*(S[i]-S[q[h]]);
// if(i==2&&j==1) cout<<dp[q[h]][j-1]<<" "<<S[2]<<" "<<(S[i]-S[q[h]+1])*(S[i]-S[q[h]+1]);
// if(j==1) continue;
while(h<t&&up(q[t],q[t-1],j)*down(i,q[t],j)>=up(i,q[t],j)*down(q[t],q[t-1],j)) t--;
q[++t]=i;
}
}
// PER(i,1,n){puts("");PER(j,0,m)cout<<dp[i][j]<<" ";}
cout <<(dp[n][m]-sq[n])/2<< endl;
}