1.​​题目链接​​。题目大意:给定一些点,每个点都有两个属性:key-value.现在可以做这样的操作,可以移除一些连续的点,条件是需要这些点的key不互质,那么得到的value是移除的所有点的value之和。现在求出这个最大的value值。

2.对于区间[l,r]我们首先预处理这个区间是不是可以移除掉。区间[l,r]可以被移除的条件很容易考虑到:其实可以从三个区间转移过来。[l+1,r-1],[l+2,r],[l,r-2].这三个区间如果有任意一个满足小区间的端点大区间的端点不互质,就可以从小区间转移过来。这样预处理之后,我们就知道了任意区间是否可以合并的信息,然后区间dp[i][j]表示区间[i][j]的最大值,如果发现这个区间是可以合并的,那么就是这个区间的所有元素的值。所以在这里我们为了可以O(1)求得这个值,还需要做一个前缀和。如果发现不能合并,就在区间里找一个点,取最大值即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 330;
#define ll long long
ll dp[maxn][maxn];
ll a[maxn], v[maxn], g[maxn][maxn];
ll gcd(ll a, ll b) { return !b ? a : gcd(b, a%b); }
ll presum[maxn];
#pragma warning(disable:4996)
int main()
{
int T;
scanf("%d", &T);
int n;
while (T--)
{
memset(g, 0, sizeof(g));
memset(dp, 0, sizeof(dp));
memset(presum, 0, sizeof(dp));
scanf("%d", &n);
for (int i = 1; i <= n; i++)scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &v[i]);
presum[i] = presum[i - 1] + v[i];
}
for (int i = 1; i <= n; i++)
{
if (gcd(a[i], a[i - 1]) > 1)g[i][i - 1] = 1;
}
for (int len = 2; len <= n; len += 2)
{
for (int j = 1; j + len - 1 <= n; j++)
{
int l = j, r = len + j - 1;
if (g[l + 1][r - 1] && gcd(a[l], a[r]) > 1)g[l][r] = 1;
if (gcd(a[l + 1], a[l]) > 1 && g[l + 2][r])g[l][r] = 1;
if (gcd(a[r - 1], a[r]) > 1 && g[l][r - 2])g[l][r] = 1;

}
}
for (int len = 2; len <= n; len++)
{
for (int j = 1; j <= n - len + 1; j++)
{
int l = j, r = j + len - 1;
if (g[l][r])dp[l][r] = presum[r] - presum[l - 1];
else
{
for (int k = l; k < r; k++)
{
dp[l][r] = max(dp[l][r], dp[l][k] + dp[k + 1][r]);
}
}
}
}
cout << dp[1][n] << endl;
}
}