题意:n<=300 对数a[i]和b[i],如果相邻的a(a[i] 和 a[i+1])的gcd不等于1,那么就可以得到b[i] + b[i+1],然后就可以去掉这一对,然后他们两边的合并起来,问最后最大可以得到多大
题解:很明显,区间dp
感觉像是括号配对一样,要不是()()这样,要不就是(())这样
但需要注意的是,类似于(())这样时,里面的()必须是完全去掉
int T,n,a[310],b[310],c[310][310];
///c用于记录里面是否是完全使用
LL dp[310][310];
void donggui(){
for(int i=2;i<=n;i++){
for(int j=i-1;j>=1;j--){
if(i-j==1){
if(__gcd(a[i],a[j])!=1){
dp[j][i]=max((LL)b[i]+b[j],dp[j][i]);
c[j][i]=1;
}
}
else {
if(c[j+1][i-1] && __gcd(a[i],a[j])!=1){
dp[j][i]=max(dp[j][i],dp[j+1][i-1]+(LL)b[i]+b[j]);
c[j][i]=1;
}
}
for(int k=j;k<=i;k++){
if(k+1>=j && k+1<=i){
if(dp[j][i] < dp[j][k]+dp[k+1][i]){
dp[j][i]=max(dp[j][i],dp[j][k]+dp[k+1][i]);
///如果两边是完全使用的话,这段也是完全使用
if(c[j][k] && c[k+1][i]){
c[j][i]=1;
}
///否则,这段就不是完全使用
else {
c[j][i]=0;
}
}
}
}
}
}
}
int main(){
while(scanf("%d",&T)!=EOF){
while(T--){
memset(dp,0,sizeof(dp));
memset(c,0,sizeof(c));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
for(int i=1;i<=n;i++)
scanf("%d",b+i);
donggui();
LL ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans=max(ans,dp[i][j]);
}
}
cout<<ans<<endl;
}
}
return 0;
}