题意:
给定长度为n的序列,每个位置是一个键值对(键,值),
一次操作你可以选择两个相邻的位置,
如果他们的键不是互质的,那么可以删去他们,然后将剩余部分拼接。
你可以操作无数次,问删除的值的最大总和是多少。
数据范围:n<=300,(键,值)<=1e9
解法:
区间dp.
令d[i][j]表示区间[i,j]能获得的最大权值.
转移有两种:
1.d[i][j]=d[i][k]+d[k+1][j].
2.设键值对为(a,b),如果d[i+1][j-1]=sum(b[i+1,j-1]),那么说明i和j能够相邻,
如果此时gcd(a[i],a[j])!=1,那么d[i][j]=b[i]+b[j]+d[i+1][j-1].
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int d[333][333];
int g[333][333];
int sum[333];
int a[333];
int b[333];
int n;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
sum[i]=sum[i-1]+b[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
d[i][j]=0;
g[i][j]=__gcd(a[i],a[j]);
}
}
for(int len=1;len<=n;len++){
for(int i=1;i<=n;i++){
int j=i+len-1;
if(j>n)break;
if(len==1)d[i][j]=0;
else if(len==2){
if(g[i][j]!=1)d[i][j]=b[i]+b[j];
}else{
if(g[i][j]!=1){
if(d[i+1][j-1]==sum[j-1]-sum[i]){
d[i][j]=max(d[i][j],b[i]+b[j]+d[i+1][j-1]);
}
}
for(int k=i;k<j;k++){
d[i][j]=max(d[i][j],d[i][k]+d[k+1][j]);
}
}
}
}
cout<<d[1][n]<<endl;
}
signed main(){
ios::sync_with_stdio(0);
int T;cin>>T;
while(T--){
solve();
}
return 0;
}