码迷,mamicode.com
首页 > 其他好文 > 详细

Mid-Atlantic 2008 Lawrence of Arabia /// 区间DP oj21080

时间:2018-07-09 16:32:24      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:hid   i+1   区间   其他   col   none   分享图片   isp   set   

题目大意:

输入n,m

输入n个数

将n个数切割m次分为m+1段,使得各段的Strategic Value总和最小

一组数a b c d的SV值为 a*b + a*c + a*d + b*c + b*d + c*d

即 a*( b+c+d ) + b*( c+d ) + c*d

Sample Input

4 1
4 5 1 2
4 2
4 5 1 2
0 0

Sample Output

17
2

 

首先将 原数组a[] 处理出后缀和 s[] 

计算出n个数中任意两点之间的SV值 sum[ i ][ j ]

1.任意点到最后一点的SV值 sum[ i ][ n ] = sum[ i+1 ][ n ] + a[ i ] * s[ i+1 ]

如 2 3 4,sum(2到n)=sum(3到n)+2*(3+4)

2.其他情况 sum[ i ][ j ] = sum[ i ][ j+1 ] - (s[ i ]-s[ j+1 ])* a[ j+1]

如 2 3 4 5 6,sum(2到4)=sum(2到5)-(2+3+4)*5

得到任意两点间的SV值后 按区间dp的方法 

i 为末尾位置,j 为切割次数,k 为切割点

则 dp[ i ][ j ] = min( dp[ i ][ j ] , dp[ k ][ j-1 ]+sum[ k+1 ][ i ] )

技术分享图片
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m,a[1005],s[1005];
int sum[1005][1005],dp[1005][1005];
int main()
{
    while(~scanf("%d%d",&n,&m)) {
        if(n+m==0) break;
        a[n]=s[n]=0;
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        for(int i=n-1;i>=0;i--) s[i]=a[i]+s[i+1];

        memset(sum,0,sizeof(sum));
        for(int i=n-2;i>=0;i--)
            sum[i][n-1]=sum[i+1][n-1]+a[i]*s[i+1];
        for(int i=n-2;i>=1;i--)
            for(int j=i-1;j>=0;j--)
                sum[j][i]=sum[j][i+1]-((s[j]-s[i+1])*a[i+1]);

        memset(dp,INF,sizeof(dp));
        for(int i=0;i<n;i++) dp[i][0]=sum[0][i];
        for(int i=1;i<=m;i++)
            for(int j=i;j<n;j++)
                for(int k=i-1;k<j;k++)
                    dp[j][i]=min(dp[j][i],dp[k][i-1]+sum[k+1][j]);
        printf("%d\n",dp[n-1][m]);
    }

    return 0;
}
View Code

 

Mid-Atlantic 2008 Lawrence of Arabia /// 区间DP oj21080

标签:hid   i+1   区间   其他   col   none   分享图片   isp   set   

原文地址:https://www.cnblogs.com/zquzjx/p/9284169.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!