hdu_5900_QSC and Master(区间DP)

题目链接:hdu_5900_QSC and Master

题意:

有n个数,每个数有个key值,有个val,如果相邻的两个数的key的gcd大于1那么就可以得到这两个数的val的和,现在问怎么取使得到的和最大

注意:1 2 2 4,第2个和第3个取掉后,第一个就和第4个相邻了

题解:

这是一道区间DP题,之前没做过,比赛时没有想出怎么来DP

考虑区间dp[i][j],枚举i到j的k,然后更新一下当前的最大值

如果gcd(i,j)>1,如果i+1=j,说明是相邻的,直接相加,如果dp[i+1][j-1]=这段的区间val和,那么中间就可以取掉,说明当前的i,j可以相邻然后取掉

此时dp[i][j]=max(dp[i][j],dp[i+1][j-1]+val[i]+val[j])

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4 typedef long long ll;
 5 
 6 const int N=307;
 7 ll dp[N][N],sum[N];
 8 int T,n,val[N],a[N];
 9 
10 ll up(ll &a,ll b){if(a<b)a=b;}
11 
12 ll DP()
13 {
14     memset(dp,0,sizeof(dp));
15     F(len,1,n)for(int i=1;i+len<=n;i++)
16     {
17         int j=i+len;
18         F(k,i,j-1)up(dp[i][j],dp[i][k]+dp[k+1][j]);
19         if(__gcd(val[i],val[j])>1)
20         {
21             if(i+1==j)dp[i][j]=a[i]+a[j];
22             else if(dp[i+1][j-1]==sum[j-1]-sum[i])up(dp[i][j],dp[i+1][j-1]+a[i]+a[j]);
23         }
24     }
25     return dp[1][n];
26 }
27 
28 int main(){
29     scanf("%d",&T);
30     while(T--)
31     {
32         scanf("%d",&n);
33         F(i,1,n)scanf("%d",val+i);
34         F(i,1,n)scanf("%lld",sum+i),a[i]=sum[i];
35         F(i,2,n)sum[i]+=sum[i-1];
36         printf("%lld
",DP());
37     }
38     return 0;
39 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/5901561.html