#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int M=310;
typedef long long ll;
ll val[M],key[M],sum[M];
int table[M][M];//table[i][j] 表示i到j是否都能消完
int can[M][M];//i,j是否互质
int n;
ll dp[M][M];// dp[i][j] (i,j)区间的最大得分
// dp[i][j]= max(dp[i+1][j],dp[k+1][j]+sum[k]-sum[i-1]) //i不消除或者i和某一点k消除
ll gcd(ll a,ll b)
{
if(a%b==0)
{
return b;
}
else
return gcd(b,a%b);
}
int take(int l,int r)
{
if(l>r) return 1;//中间没东西了
else if(l==r) return 0;
else
return table[l][r];
}
void Init()
{
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(gcd(key[i],key[j])!=1)
{
can[i][j]=1;
can[j][i]=1;//
}
else
can[i][j]=can[j][i]=0;
}
}
memset(table,0,sizeof(table));
for(int len=1;len<n;len++)//区间长度
{
for(int l=1;l+len<=n;l++)//区间起点
{
int r=l+len;
for(int k=l+1;k<=r;k++)//枚举最左边应该和谁消除
{
if(can[l][k]&&take(l+1,k-1)&&take(k+1,r))
{
table[l][r]=1;
break;
}
}
}
}
}
ll Dp(int l,int r)
{
if(l>=r) return 0;
if(dp[l][r])
{
return dp[l][r];
}
for(int k=l+1;k<=r;k++)//对左端点进行决策:不消 或者 和某个点消
{
if(take(l,k))//不互质&&中间要能都消除完
{
dp[l][r]=max(dp[l][r],sum[k]-sum[l-1]+Dp(k+1,r));
}
}
Dp(l+1,r);
dp[l][r]=max(dp[l][r],dp[l+1][r]);
return dp[l][r];
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(dp,0,sizeof(dp));
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&key[i]);
}
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&val[i]);
sum[i]=sum[i-1]+val[i];
}
Init();//预处理
Dp(1,n);
cout<<dp[1][n]<<endl;
}
return 0;
}
hdu 5900 区间dp
最新推荐文章于 2021-05-25 12:54:28 发布