題意:輸入n組鍵值對,如果相鄰兩個鍵的最大公約數不爲1,那麼可以刪除這兩組鍵值對,並得到兩個值相加的分數,
問最大得分是多少。注意兩組鍵值對刪除以後會使原本不相鄰的變成相鄰。
比較明顯的區間dp,用dp[i][j]表示區間[i, j]的最大得分,對於所有的i<=k<j,dp[i][j] = max(dp[i][k] + d[k + 1][j];還有一種情況就是當刪除區間兩個端點以外的其他點以後,i和j變成相鄰的點,那麼要考慮滿足條件時,dp[i + 1][j - 1] + v[i] + v[j]是不是更優。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll dp[305][305];
ll sum[305];
ll id[305];
ll v[305];
ll gcd(ll a, ll b) {
if(b) return gcd(b, a % b);
return a;
}
int main() {
int t;
ll n, i, j, k;
scanf("%d", &t);
while(t--) {
scanf("%I64d", &n);
for(i = 0; i < n; i++)
scanf("%I64d", &id[i]);
for(i = 0; i < n; i++)
scanf("%I64d", &v[i]);
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
sum[0] = v[0];
for(i = 1; i < n; i++)
sum[i] = sum[i - 1] + v[i];
for(i = 1; i < n; i++) {
if(gcd(id[i - 1], id[i]) > 1)
dp[i - 1][i] = v[i] + v[i - 1];
}
for(i = 2; i <= n; i++) {
for(j = 0; j + i < n; j++) {
for(k = j; k < j + i; k++) {
dp[j][j + i] = max(dp[j][j + i], dp[j][k] + dp[k + 1][j + i]);
}
if(gcd(id[j], id[j + i]) > 1 && (i & 1) && dp[j + 1][j + i - 1] == sum[j + i - 1] - sum[j]) {
dp[j][j + i] = max(dp[j + 1][j + i - 1] + v[j] + v[j + i], dp[j][j + i]);
}
}
}
// for(i = 0; i < n; i++) {
// for(j = 0; j < n; j++)
// printf("%d ", dp[i][j]);
// printf("\n");
// }
printf("%I64d\n", dp[0][n - 1]);
}
return 0;
}