HDU 4283 You Are the One 区间dp

题意: 有一列人, 他们每个人有屌丝值, 每个人根据上场顺序会有不满意度, 是在他之前上场人数乘屌丝值. 现在有一个栈可以暂时人, 问最后所有人都上场最少会产生多少不满意度.

思路:

dp[i][j]表示从第i到第j个人最少产生的不满意度.

现在假设i到j已经是最优区间, 考虑i前面的人i-1:

这个人可能Ⅰ直接上场, 或者Ⅱ进栈之后在j之后上场.

那么dp[i-1][j]就会由两个值进行转移: Ⅰdp[i-1][i-1]+dp[i][j] 和 Ⅱdp[i][j]-①sum(a from i to j)+②a[i-1]*j.

Ⅰ是显然的, 主要说说Ⅱ:

因为dp[i[[j]已经是最优的区间, 我们如果不动它, 那么如果i-1这个人如果等着的话, 就必须在j之后上场. 那么i到j的人会减少①的不满意度, i-1这个人的不满意度就是②.

以上区间扩展, 当然还有区间合并, 枚举每个位置, 当前区间由两个由k分隔的区间简单相加组成.

其实Ⅰ也是区间合并的一种, 所以我在代码中并没有写Ⅰ, 只是让k在区间合并里从s开始枚举, 与Ⅰ的操作是等价的.

代码:

#include<bits/stdc++.h>

using namespace std;

void debug_out() {
    cerr << '\n';
}

template<typename T, typename ...R>
void debug_out(const T &f, const R &...r) {
    cerr << f << " ";
    debug_out(r...);
}

#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);

typedef long long ll;

const int M = 105;
const int inf = 1e9 + 5;
const int mod = 1e9 + 7;

int _;
int n;
int a[M];
int dp[M][M];

void init() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); }
    fill(dp[0], dp[0] + M * M, inf);
    for (int len = 1; len <= n; len++) {
        for (int s = 1; s + len - 1 <= n; ++s) {
            int t = s + len - 1;
            if (len == 1) {
                dp[s][t] = (s - 1) * a[s];
                continue;
            }
            int sum = 0;

            for (int i = s + 1; i <= t; i++)sum += a[i];

            dp[s][t] = dp[s + 1][t] + a[s] * (t - 1) - sum;//这里是Ⅱ
            //以上区间扩展
            for (int k = s; k < t; ++k) {//区间合并(包括Ⅰ)
                dp[s][t] = min(dp[s][t], dp[s][k] + dp[k + 1][t]);
            }
        }
    }
/*    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            printf("[%d,%d]:%d ", i, j, dp[i][j]);
        }
        puts("");
    }*/
    printf("%d\n", dp[1][n]);
}

void solve() {

}

int main() {
    int caz = 0;
    scanf("%d", &_);
    while (_--) {
        printf("Case #%d: ", ++caz);
        init();
        solve();
    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值