D. Genius DP
有 \(n\) 个问题,对于第 \(i\) 个问题 \(c_i = 2^i\) , \(tag_i\) 和 \(s_i\) ,一开始你有的 \(IQ = 0\) ,你可以从 \(u\) 走到 \(v\) 当且仅当 \(IQ<|c_i-c_j|\) 并且 \(tag_i!=tag_j\) ,同时你可以获得 \(|s_i-s_j|\) 的分数。问你最多可以获得多少分数?
首先推荐一篇写的很好的题解:https://blog.csdn.net/qq_35577488/article/details/115018266
定义:\(dp[i]\) 表示 \(i\) 是最后一个被访问的点,此时获得的最大的分数。
\((i,j,w)\) 和 \((j,i,w)\) 分数是一样的,但是状态是不一样的,假设 \(i>j\)
\(dp[i] = max(dp[i],dp[j]+w)\) 需要注意的是: \(dp[i]\) 其实隐含着从 \([j+1,i-1]\) 这个区间转移到 \(j\) ,然后再从 \(j\) 转移到 \(i\)
\(dp[j] = max(dp[j],dp[i]+w)\) 需要注意的是:\(dp[j]\) 也隐含着从 \([j+1,i-1]\) 这个区间转移到 \(i\) ,然后再从\(i\) 转移到 \(j\)
所以 \(i\) 需要从 \([2,n]\) 遍历,而 \(j\) 需要从 \([i-1,1]\) 遍历。
如果 \(j\) 从 \([1,j-1]\) 这样的遍历顺序,那么就会出现问题。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3 + 10;
typedef long long ll;
int a[maxn],tag[maxn];
ll dp[maxn];
int main(){
int T;
scanf("%d",&T);
while(T--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &tag[i]);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), dp[i] = 0;
ll ans = 0;
for (int i = 2; i <= n; i++) {
for (int j = i - 1; j >= 1; j--) {
if (tag[i] ^ tag[j]) {
long long temp = dp[i], w = abs(a[i] - a[j]);
dp[i] = max(dp[i], dp[j] + w);
dp[j] = max(dp[j], temp + w);
ans = max(ans,dp[i]);
ans = max(ans,dp[j]);
}
}
}
printf("%lld\n",ans);
}
return 0;
}
原文:https://www.cnblogs.com/EchoZQN/p/14650280.html