hdu 5900 - QSC and Master (2016瀋陽網絡賽)區間dp

題意:輸入n組鍵值對,如果相鄰兩個鍵的最大公約數不爲1,那麼可以刪除這兩組鍵值對,並得到兩個值相加的分數,

問最大得分是多少。注意兩組鍵值對刪除以後會使原本不相鄰的變成相鄰。

比較明顯的區間dp,用dp[i][j]表示區間[i, j]的最大得分,對於所有的i<=k<j,dp[i][j] = max(dp[i][k] + d[k + 1][j];還有一種情況就是當刪除區間兩個端點以外的其他點以後,i和j變成相鄰的點,那麼要考慮滿足條件時,dp[i + 1][j - 1] + v[i] + v[j]是不是更優。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll dp[305][305];
ll sum[305];
ll id[305];
ll v[305];
ll gcd(ll a, ll b) {
    if(b) return gcd(b, a % b);
    return a;
}
int main() {
    int t;
    ll n, i, j, k;
    scanf("%d", &t);
    while(t--) {
        scanf("%I64d", &n);
        for(i = 0; i < n; i++)
            scanf("%I64d", &id[i]);
        for(i = 0; i < n; i++)
            scanf("%I64d", &v[i]);
        memset(dp, 0, sizeof(dp));
        memset(sum, 0, sizeof(sum));
        sum[0] = v[0];
        for(i = 1; i < n; i++)
            sum[i] = sum[i - 1] + v[i];
        for(i = 1; i < n; i++) {
            if(gcd(id[i - 1], id[i]) > 1)
                dp[i - 1][i] = v[i] + v[i - 1];
        }
        for(i = 2; i <= n; i++) {
            for(j = 0; j + i < n; j++) {
                for(k = j; k < j + i; k++) {
                    dp[j][j + i] = max(dp[j][j + i], dp[j][k] + dp[k + 1][j + i]);
                }
                if(gcd(id[j], id[j + i]) > 1 && (i & 1) && dp[j + 1][j + i - 1] == sum[j + i - 1] - sum[j]) {
                    dp[j][j + i] = max(dp[j + 1][j + i - 1] + v[j] + v[j + i], dp[j][j + i]);
                }
            }
        }
//        for(i = 0; i < n; i++) {
//            for(j = 0; j < n; j++)
//                printf("%d ", dp[i][j]);
//            printf("\n");
//        }
        printf("%I64d\n", dp[0][n - 1]);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章