模板一套就AC了...
guardians.cpp 1S/128M
你负责将监狱的警卫指派到最疯狂的罪犯所在的监狱。 一共有N间牢房排列成一行,编号从1~N。 第i间牢房恰好容纳了一个疯狂程度为C[i]的罪犯。
每个罪犯都应该有一个警卫监视他/她。 理想情况下,应该让一名警卫监视一个罪犯。 然而,由于预算限制,你只能分配G个警卫。 为了最大程度地降低有人逃脱的总风险,你必须指定每个警卫应该监视哪些罪犯。当然,你应该将每个警卫分配给一组相邻的牢房。
第i个罪犯可能逃脱的风险R[i]由下式给出:
R[i] = C[i] * 指派监视他的警卫监视的罪犯数量
请你分配一个最佳的方案,使所有罪犯的风险之和最小。
输入
第1行:2个整数N和G (1 <= N <= 8000, 1 <= G <= 800)
第2行:N个整数,表示C[i] ( 1 <= C[i] <= 10^9)
输出
第1行:1个整数,表示答案
Sample Input
6 3
11
11
11
24
26
100
Sample Output
299
Explain
第1个警卫监视1~3,第2个警卫监视4~5,第3个警卫监视6
详细的关于该优化的讲解我有写博客:决策单调性分治优化
经观察可以发现本题基本模型为:分组+花费最小
可以写出DP定义与转移方程:
dp[ i ][ j ]:1~j个犯人被第i个狱长监管
对于最后一个狱长i,假设从第k到j的犯人被最后第i狱长监管
dp[ i ][ j ]=min( dp[ i ][ j ],dp[ i-1 ][ k-1 ]+( s[ j ] - s[ k ] ) * ( j - k + 1 ) ) ;
s[ i ]:1~i的前缀和
初始化:dp[ 1 ][ 1~n ]=INF
然后直接套用【决策单调性分治优化】或【四边形不等式优化】即可,详见代码
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN=8000,MAXG=800;
#define INF (1LL << 60)
ll c[MAXN+5],s[MAXN+5],dp[MAXG+5][MAXN+5];
ll n,g;
void DP(ll d,ll i,ll j,ll optl,ll optr)//决策优化
{
if(i>j)
return ;
ll mid=(i+j)/2;
ll opt=INF,id;
//暴力计算二分点的dp值opt与最小决策点id
for(int k=optl;k<=min(mid,optr);k++)
{
ll cur=dp[d-1][k-1]+(mid-k+1)*(s[mid]-s[k-1]);
if(cur
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN=8000,MAXG=800;
#define INF (1LL<<60)
ll c[MAXN+5],s[MAXN+5],dp[MAXG+5][MAXN+5];
ll n,g;
void Solve()
{
for(int i=0;i<=g;i++)
for(int j=0;j<=n;j++)
dp[i][j]=INF;
dp[0][0]=0;
for(int i=1;i<=g;i++)
{
ll opt=0;
for(int j=i;j<=n;j++)
for(int k=opt;k<=j;k++)
{
ll tmp=1ll*(j-k+1)*(s[j]-s[k-1]);
if(dp[i-1][k-1]+tmp<=dp[i][j])
dp[i][j]=dp[i-1][k-1]+tmp,opt=k;
}
}
/*打表验证单调性
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
w[i][j]=(j-i+1)*(s[j]-s[i-1]);
//printf("%d %d %lld\n",i,j,w[i][j]);
}
for(int a=1;a<=n;a++)
for(int b=a+1;b<=n;b++)
for(int c=b+1;c<=n;c++)
for(int d=c+1;d<=n;d++)
printf("%d %d %d %d %lld %lld\n",a,b,c,d,w[a][c]+w[b][d],w[a][d]+w[b][c]);
*/
printf("%lld\n",dp[g][n]);
}
int main()
{
scanf("%lld%lld",&n,&g);
for(int i=1;i<=n;i++)
{
scanf("%lld",&c[i]);
s[i]=s[i-1]+c[i];
}
Solve();
return 0;
}