[ifrog 1074 Pick Up Coins] 区间DP

[ifrog 1074 Pick Up Coins] 区间DP

1. 题目链接

[ifrog 1074 Pick Up Coins]

2. 题意描述

n 个硬币,第i个价值为 vi ,从中取出第 i 个硬币,你将获得价值vi1vivi+1。求将 n 个硬币全部取出来的能获得的最大价值。
假定v0=vn+1=1.
3n103

3. 解题思路

dp[i][j] 表示区间 [i,j] 中能够获得最大价值。那么可以写出转移方程:

dp[i][j]=max{dp[i][k1]+dp[k+1][j]+vi1vkvj+1}

4. 实现代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

const int MAXN = 1e3 + 5;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;

int n;
LL a[MAXN];
LL dp[MAXN][MAXN];
/**
暴力查错
void del(vector<LL>& L, vector<LL>& R, int x) {
    L[R[x]] = L[x];
    R[L[x]] = R[x];
}

LL special(int s, int sz) {
    vector<LL> b(sz + 2), L(sz + 2), R(sz + 2), gen(sz);
    b[0] = b[sz + 1] = 1;
    for(int i = 0; i < sz; i++) {
        gen[i] = i + 1;
        b[i + 1] = a[i + s];
    }
    LL ret = 0;
    do{
        for(int i = 0; i <= sz + 1; i++) L[i] = i - 1, R[i] = i + 1;
        LL val = 0;
        for(int i = 0; i < sz; i++) {
            LL id = gen[i];
            val += b[L[id]] * b[id] * b[R[id]];
            del(L, R, id);
        }
        ret = max(ret, val);
    }while(next_permutation(gen.begin(), gen.end()));
    return ret;
}
*/
void solve() {
    memset(dp, 0, sizeof(dp));
    a[0] = a[n + 1] = 1;
    dp[0][0] = dp[n + 1][n + 1] = 1;
    for(int i = 1; i <= n; i++) {
        dp[i][i] = a[i - 1] * a[i] * a[i + 1];
    }
    for(int len = 2; len <= n; len++) {
        for(int i = 1; i + len - 1 <= n; i++) {
            int j = i + len - 1;
            for(int k = i; k <= j; k++) {
                LL v = dp[i][k - 1] + dp[k + 1][j] + a[i - 1] * a[k] * a[j + 1];
                if(dp[i][j] < v) dp[i][j] = v;
            }
        }
    }
}
int main() {
#ifdef ___LOCAL_WONZY___
    freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    int _;
    scanf("%d", &_);
    while(_ --) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
        }
        solve();
        printf("%lld\n", dp[1][n]);
//        printf("%lld\n", special(1, n));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值