题目链接
定义状态dp[i]表示打印前i个单词的最小成本。
dp[i] = min(dp[j] + (sum[i] – sum[j]) ^ 2)
dp[i] = min(dp[j] + sum[j]^2 – 2*sum[i]*sum[j]) + sum[i]^2
dp[j] + sum[j]^2 –(dp[k] + sum[k]^2) < 2*sum[i]*(sum[j] – sum[k])
只需要用斜率优化即可。
由于此题比较基础,所以代码故意写复杂一点一边理解,在以后较难题目中将贴出简略代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define N 500000 + 10
#define LL long long
#define cls(a) memset( a, 0, sizeof(a))
struct P{
LL x, y;
};
P q[N];
int m, n;
LL dp[N], c[N], sum[N];
int l, r;
P operator - ( P a, P b ){
P p;
p.x = a.x - b.x;
p.y = a.y - b.y;
return p;
}
LL operator * ( P a, P b ){
return a.x * b.y - b.x * a.y;
}
bool init(){
if( scanf( "%d%d", &n, &m) == EOF ) return false;
cls(c), cls(sum), cls(dp), cls(q);
for ( int i = 1; i <= n; i++) scanf( "%d", &c[i]);
sum[0] = 0;
for ( int i = 1; i <= n; i++) sum[i] = sum[i-1] + c[i];
l = 1, r = 2;
dp[0] = 0, dp[1] = m+sum[1]*sum[1];
q[1].x=sum[1], q[1].y=dp[1]+sum[1]*sum[1];
return true;
}
void insert( LL x, LL y ){
P p;
p.x = x, p.y = y;
for (; l<r && (p-q[r-1])*(q[r]-q[r-1]) >= 0;r--);
q[++r]=p;
}
void Dp(){
for ( int i = 1; i <= n; i++){
LL k = 2*sum[i];
for (; l<r && q[l].y-q[l].x*k > q[l+1].y-q[l+1].x*k;l++);
dp[i] = q[l].y - k * q[l].x + sum[i]*sum[i] + m;
insert( sum[i], sum[i]*sum[i]+dp[i]);
}
printf( "%d\n", dp[n]);
}
int main(){
while ( init() ){
Dp();
}
return 0;
}
*/