D. Genius DP

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;
}
posted @ 2021-04-12 20:49  EchoZQN  阅读(61)  评论(0编辑  收藏  举报