区间dp,状态转移就是枚举中间点k或者取两边,其中取两边需要中间能取干净才能取。
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 300 + 10;
struct pair {
int key, val;
};
pair a[maxn];
long long sum[maxn];
long long dp[maxn][maxn];
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
bool check(int a, int b) {
return gcd(a, b) > 1;
}
int main(int argc, char const *argv[]) {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i].key);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i].val);
sum[i] = a[i].val + sum[i-1];
}
memset(dp, 0, sizeof(dp));
for (int l = 1; l <= n; l++) {
for (int i = 1; i + l <= n; i++) {
int j = i + l;
if (check(a[i].key, a[j].key)) {
if (i + 1 == j) {
dp[i][j] = a[i].val + a[j].val;
} else if (dp[i+1][j-1] == sum[j-1] - sum[i]) {
dp[i][j] = std::max(dp[i][j], dp[i+1][j-1] + a[i].val + a[j].val);
}
}
for (int k = i; k < j; k++) {
dp[i][j] = std::max(dp[i][j], dp[i][k] + dp[k+1][j]);
}
}
}
printf("%lld\n", dp[1][n]);
}
return 0;
}