题意:
有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 }