HDU5900QSC and Master (區間DP)

題意:

就是給你一個序列,每一個key值對應一個value值,可以把兩個連續的key值gcd!=1的對取出來,獲取他們的價值,在它們連邊的數字因此也變得連續了,問能獲取的最大價值

分析:

枚舉區間,如果兩端不互素且中間部分全取,則dp[i][j]=dp[i+1][j-1]+value[i]+value[j];,判斷全取就用前綴和判斷,否則就枚舉中間點k進行更新。


分析轉自:點擊打開鏈接

區間DP還沒有寫過,感覺套路不深,趕緊去學一學!

代碼:

#include <set>
#include <map>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define PI acos(-1.0)
#define MOD 1000000009
#define INF 0x3f3f3f3f
#define Lowbit(x) (x & (-x))
#define mem(a,x) memset(a,x,sizeof(a))
#define Read()  freopen("in.txt", "r", stdin);
#define Write() freopen("out.txt", "w", stdout);
#define bitnum(a) __builtin_popcount(a)
using namespace std;
typedef long long int ll;
inline int in()
{
    int res=0;char c;int f=1;
    while((c=getchar())<'0' || c>'9')if(c=='-')f=-1;
    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
const int maxn = 305;
ll dp[maxn][maxn];
ll key[maxn];
ll val[maxn];
ll sum[maxn];
int n;
ll gcd(ll a, ll b){
    return b == 0 ? a: gcd(b,a%b);
}
void DP(){
    mem(dp,0);
    for(int len=1;len<=n;len++){ //區間長度
        for(int i=1;i+len<=n;i++){
            int j = i + len;
            for(int k=i;k<j;k++)
                dp[i][j] = max(dp[i][j],dp[i][k] + dp[k+1][j]); //枚舉中間點K進行更新

            if(gcd(key[i] , key[j]) >1){
                if(j == i + 1) dp[i][j] = val[i] + val[j];
                else if(dp[i+1][j-1] == sum[j-1] - sum[i])
                    dp[i][j] = max(dp[i][j],dp[i+1][j-1] + val[i] + val[j]);
            }
        }
    }
    printf("%lld\n",dp[1][n]);
}
int main(){
    int T = in();
    while(T--){
        mem(sum,0);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) key[i] = in();
        for(int i=1;i<=n;i++) val[i] = in() , sum[i] = sum[i-1] + val[i];
        DP();
    }
}

用剛學的姿勢過了一發。

typedef long long int ll;
inline int in()
{
    int res=0;char c;int f=1;
    while((c=getchar())<'0' || c>'9')if(c=='-')f=-1;
    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
ll dp[2005][2005] , a[105];
ll key[322];
ll val[322];
ll sum[333];
ll gcd(ll n, ll m){
    return m == 0 ? n: gcd(m,n%m);
}
int main(){
    int T = in();
    while(T--){
        int n = in();
        for(int i=1;i<=n;i++) key[i] = in();
         mem(sum,0);
        for(int i=1;i<=n;i++) {
          val[i] = in();
          sum[i] = val[i] + sum[i-1];
        }
        mem(dp,0);
        for(int i=n-1;i>=1;i--){
            for(int j=i+1;j<=n;j++){
                for(int k=i+1;k<=j;k++){
                    dp[i][j] = max(dp[i][j],dp[i][k-1] + dp[k][j]); //必須枚舉一遍,找到最大的分割點
                }

                if(gcd(key[i],key[j]) > 1 ){
                   if(j == i+1)
                        dp[i][j] = val[i] + val[j];
                    else if(dp[i+1][j-1] == sum[j-1] - sum[i]){
                        dp[i][j] = dp[i+1][j-1] + val[i]+ val[j];
                    }
                }

            }
        }
        printf("%lld\n",dp[1][n]);
    }
    return 0;
}


發佈了257 篇原創文章 · 獲贊 148 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章