zoukankan      html  css  js  c++  java
  • HDU 5900 QSC and Master (区间DP)

    题意:给出n对数keyi,vali表示当前这对数的键值和权值,可以操作将连续的两个数合并,如果满足gcd(a[i],a[i+1])>1,得到的价值是两个数的权值和,

    每次合并两个数之后,这两个数就会消失,然后旁边的数会接上.

    析:区间DP,首先dp[i][j] 表示区间第 i 段到第 j 段所能得到的最大值,然后分情况讨论一下,第一种是区间内的所有的都可以合并,这个预处理一下就好,

    第二种不能全合并,那么选取最大的那一个就好。

    代码如下:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #include <tr1/unordered_map>
    #define freopenr freopen("in.txt", "r", stdin)
    #define freopenw freopen("out.txt", "w", stdout)
    using namespace std;
    using namespace std :: tr1;
    
    typedef long long LL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const double inf = 0x3f3f3f3f3f3f;
    const LL LNF = 0x3f3f3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 3e2 + 5;
    const int mod = 1e9 + 7;
    const int N = 1e6 + 5;
    const int dr[] = {-1, 0, 1, 0};
    const int dc[] = {0, 1, 0, -1};
    const char *Hex[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline int Min(int a, int b){ return a < b ? a : b; }
    inline int Max(int a, int b){ return a > b ? a : b; }
    inline LL Min(LL a, LL b){ return a < b ? a : b; }
    inline LL Max(LL a, LL b){ return a > b ? a : b; }
    inline bool is_in(int r, int c){
        return r >= 0 && r < n && c >= 0 && c < m;
    }
    LL sum[maxn];
    LL dp[maxn][maxn], a[maxn], val[maxn];
    bool f[maxn][maxn];
    
    int main(){
        int T;   cin >> T;
        while(T--){
            scanf("%d", &n);
            for(int i = 1; i <= n; ++i)  scanf("%I64d", &a[i]);
            for(int i = 1; i <= n; ++i){
                scanf("%I64d", &val[i]);
                sum[i] = sum[i-1] + val[i];
            }
    
            memset(f, false, sizeof f);
            for(int i = 1; i < n; ++i)  f[i][i+1] = __gcd(a[i], a[i+1]) != 1;
    
            for(int i = 2; i <= n; i += 2){
                for(int j = 1; j+i-1 <= n; ++j){
                    int k = j+i-1;
                    if(__gcd(a[k-1], a[k]) != 1 && f[j][k-2])  f[j][k] = true;
                    else if(__gcd(a[j+1], a[j]) != 1 && f[j+2][k])  f[j][k] = true;
                    else if(__gcd(a[j], a[k]) != 1 && f[j+1][k-1])  f[j][k] = true;
                }
            }
    
            memset(dp, 0, sizeof dp);
            for(int i = 2; i <= n; ++i){
                for(int j = 1; j+i-1 <= n; ++j){
                    int l = j+i-1;
                    if(f[j][l])  dp[j][l] = sum[l] - sum[j-1];
                    else{
                        for(int k = j; k < l; ++k)
                            dp[j][l] = Max(dp[j][l], dp[j][k] + dp[k+1][l]);
                    }
                }
            }
            printf("%I64d
    ", dp[1][n]);
        }
        return 0;
    }
    
  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/5888506.html
Copyright © 2011-2022 走看看