HDU-5900 QSC and Master
题目大意:
有n对二元组(key, value),两个相邻的元组间如果key的不互质,那么可以被移除,并获得两个元组的value值之和的分数,问你最多能有多少分数。
解题思路:
区间DP
按照最裸的区间DP模型用记忆化搜索写是要超时的...
本题的模型可以参考POJ-2955 Brackets题解这里有~
设dp[i][j]表示区间[i, j]能获得的最大分数状态转移就可以写成
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j], dp[i+1][j-1] + value[i] + value[j]);
剩下的就很简单了。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 305; bool judge[maxn][maxn]; pair<int, int> p[maxn]; LL sum[maxn], dp[maxn][maxn]; LL gcd(LL a, LL b) { while (b) { LL tmp = a % b; a = b; b = tmp; } return a; } int main() { int n, t; scanf("%d", &t); while (t--) { scanf("%d", &n); sum[0] = 0; for (int i = 1; i <= n; ++i) scanf("%d", &p[i].first); for (int i = 1; i <= n; ++i) { scanf("%d", &p[i].second); sum[i] = sum[i - 1] + p[i].second; } memset(judge, false, sizeof(judge)); for (int i = 1; i <= n; ++i) { for (int j = i + 1; j <= n; ++j) judge[i][j] = (gcd(p[i].first, p[j].first) == 1 ? false : true); } for (int i = n; i >= 1; --i) { for (int j = i; j <= n; ++j) { dp[i][j] = 0; for (int k = i; k < j; ++k) dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j]); if ((i + 1 == j || dp[i + 1][j - 1] == sum[j - 1] - sum[i]) && judge[i][j]) dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + p[i].second + p[j].second); } } printf("%lld\n", dp[1][n]); } return 0; }