hdu5900
题目
就是给你一个序列,每一个key值对应一个value值,可以把两个连续的key值gcd!=1的对取出来,获取他们的价值,在它们连边的数字因此也变得连续了,问能获取的最大价值。
思路
看出来了是区间dp,也和同学讨论过了,但是还是太没自信+不敢相信自己,其实正解离我们的WA代码差的不远,回头改了一下就过了。
就是枚举区间,如果两端不互素且中间部分全取,则dp[i][j]=dp[i+1][j-1]+value[i]+value[j];,判断全取就用前缀和判断,否则就枚举中间点k进行更新。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=310;
ll gcd(ll x,ll y)
{
int t;
while (y) t=x, x=y, y=t%y;
return x;
}
ll key[maxn],value[maxn];
ll dp[maxn][maxn],sum[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%I64d",&key[i]);
sum[0]=value[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%I64d",&value[i]);
sum[i]=sum[i-1]+value[i];
}
for(int i=1; i<n; i++)
if(gcd(key[i],key[i+1])!=1)
dp[i][i+1]=value[i]+value[i+1];
for(int len=3; len<=n; len++)
{
for(int i=1; i+len-1<=n; i++)
{
int j=i+len-1;
if(gcd(key[i],key[j])!=1)
{
if(dp[i+1][j-1]==sum[j-1]-sum[i])
dp[i][j]=dp[i+1][j-1]+value[i]+value[j];
else
for(int k=2; i+k-1<=j; k+=2)
{
int t=i+k-1;
dp[i][j]=max(dp[i][j],dp[i][t]+dp[t+1][j]);
}
}
else
{
for(int k=1; i+k-1<=j; k++)
{
int t=i+k-1;
dp[i][j]=max(dp[i][j],dp[i][t]+dp[t+1][j]);
}
}
}
}
printf("%I64d\n",dp[1][n]);
}
return 0;
}