• 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
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    【Alpha】测试报告
    【Alpha】发布说明
    【Alpha】项目展示
    【Alpha】Scrum Meeting 10
    【Alpha】Scrum Meeting 9
    【Alpha】Scrum Meeting 8
    “北航Clubs”功能规格说明书
    后端技术规格说明书
    前端设计说明书
    Daily Scrumming* 2015.11.3(Day 15)
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14650280.html
Copyright © 2020-2023  润新知