B — Snakes
题目大意:
根据传说,一千多年前,圣帕特里克驱逐了穆尔兰的所有蛇。然而,从那以后,蛇又回到了穆尔兰!圣帕特里克节是在3月17日,所以贝西要永远地从穆尔兰赶走所有的蛇来纪念圣帕特里克。贝西配备有网,可以捕捉N组分布在一条线上的蛇(1≤N≤400)。贝西必须按照每组蛇出现在这条线上的顺序,把每条蛇都抓起来。每次贝西抓住一群蛇,她可以把蛇放在笼子里,然后用空网开始下一群。大小为s的网意味着贝西可以捕获任何含有g条蛇的组,其中g≤s。然而,每当贝西用一张s码的网捕获一群g码的蛇时,她就浪费了s - g码的空间。贝西的网兜可以从任何大小开始,她可以改变网兜的大小K次(1≤K<N)。请告诉贝西,在捕获所有组后,她可以积累的总浪费空间的最小数量。
输入
第一行包含N和K,
第二行包含N个整数,a1,…,aN,其中ai(0≤ai≤106)是第i组的蛇的数量。
输出
输出一个整数,给出贝西捕获所有蛇后的最小浪费空间量。
题目分析:
每次使用变形,都可以抓捕连续的几组蛇,假如使用1次变形抓捕区间[l,r]组的蛇,那么这个区间最小浪费为maxa*(r-l)-(sum[r]-sum[l]),其中maxa为[l,r]组最多的数目,sum[r]为前r组蛇的总数。
假设现在考虑抓捕第i组,使用m次变形,记为dp[i][m],运用动态规划思想,那么dp[i][m]=min(dp[j][m-1]+maxa*(i-j)-(sum[i]-sum[j])) (1<=j<i,maxa为[j+1,i]最大值)。
代码实现:
#include <iostream>
#include <cstdio>
using namespace std;
const int INF = 999999999;
int n,k;
int a[457];
int sum[457] = {0};
int ans[457][457];
void init()
{
for(int i=0; i<457; i++)
{
for(int j=0; j<457; j++)
{
ans[i][j] = INF;
}
}
}
int dp()
{
for(int m=1; m<=k; m++)
{
for(int i=m+1; i<=n; i++) //m次变形最少也要m组蛇,所有m+1开始
{
int maxa = 0;
for(int j=i-1; j>=m; j--)
{
maxa = max(maxa,a[j+1]);
ans[i][m] = min(ans[i][m],ans[j][m-1]+maxa*(i-j)-(sum[i]-sum[j]));
}
}
}
return ans[n][k];
}
int main()
{
init(); //初始化
cin >> n >> k;
int maxa = 0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum[i] = sum[i-1]+a[i]; //前i堆蛇总数,即前缀和
maxa = max(maxa,a[i]); //前i最大数
ans[i][0] = maxa*i-sum[i]; //第0次变形时,前i次抓捕的最小浪费
}
printf("%d\n",dp());
return 0;
}