http://acm.hdu.edu.cn/showproblem.php?pid=5900
题意:给n个数有key和val,相邻的并且key不互质的两个数可以消去并得到val,问最大价值之和
区间dp
状态表示:d[i][j] = 区间[i, j]能获得的最大值
转移的话对于i到j区间 我一直在想怎么由i到k和k+1到j合并,然后合并时,怎么考虑左区间右端点和右区间左端点的合并。
确实根本不需要考虑
只需要考虑两种转移:
1: dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
2: 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]); 【中间都被合并了,则最两端可以合并】
对于刚才说的区间端点是否可以合并的情况,已经会包含在第二种转移之中,因此这样就简单地完成了状态转移.
#include<bits/stdc++.h>
using namespace std;
const int N=305;
typedef long long ll;
ll key[N],val[N],sum[N],dp[N][N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for (int i=1;i<=n;i++)
scanf("%lld",&key[i]);
for (int i=1;i<=n;i++)
scanf("%lld",&val[i]),sum[i]=sum[i-1]+val[i];
memset(dp,0,sizeof dp);
for (int l=2;l<=n;l++)
{
for (int i=1;i+l-1<=n;i++)
{
int j=i+l-1;
for (int k=i;k<j;k++)
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
if (__gcd(key[i],key[j])!=1)
{
if (j==i+1) dp[i][j]=max(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]);
}
return 0;
}