zoukankan      html  css  js  c++  java
  • CF1370D.Odd-Even Subsequence 题解 动态规划+二分

    题目链接:https://codeforces.com/problemset/problem/1370/D

    解题思路:

    一开始的想法是定义状态 (dp_{i,j}) 表示“前 (i) 个数,选了第 (i) 个数,共选了 (j) 个数的最小值”。则状态转移方程为(没有验证过):

    [dp_{i,j} = min_{k in [0,i-2]} { dp_{k,j-2}, a_i } ]

    但是就算状态压缩,遍历的状态就达到了 (O(n^2)),肯定是超时的。

    然后考虑二分答案+DP,假设最大值较小的那个序列的最大值取 (D),然后 (dp[i]) 表示 (a_i) 对应的那个奇偶性的子序列的最小值不超过 (D) 并且选了 (a_i) 的情况下最多能选多少数。

    状态转移方程为:

    (dp[i] = max { dp[k] } + 2)

    其中 (k) 满足 (k le i-2)(dp[k] le D)

    状态转移可以用 单调队列/单调栈 (抱歉,只需要一个到 (i-2) 的数表示满足条件的最大值即可)优化。

    则最终只要存在一个 (dp[i] ge k) 或者存在一个 (i lt n) 满足 (dp[i] ge k-1),则 (D) 可作为一个正确的答案,对此进行二分。

    示例代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200020;
    int n, k, a[maxn], dp[maxn];
    bool check(int D) {
        int tmp = 0;
        for (int i = 1; i <= n; i ++) {
            if (i == 1) {
                dp[i] = (a[i] <= D) ? 1 : 0;
            }
            else {
                tmp = max(tmp, dp[i-2]);
                if (a[i] > D) dp[i] = 0;
                else dp[i] = tmp + 2;
            }
            if (i < n && dp[i] >= k-1 || dp[i] >= k) return true;
        }
        return false;
    }
    int main() {
        scanf("%d%d", &n, &k);
        int L = 1, R = 0, res;
        for (int i = 1; i <= n; i ++) {
            scanf("%d", a+i);
            R = max(R, a[i]);
        }
        while (L <= R) {
            int mid = (L + R) / 2;
            if (check(mid)) {
                res = mid;
                R = mid - 1;
            }
            else L = mid + 1;
        }
        printf("%d
    ", res);
        return 0;
    }
    
  • 相关阅读:
    xhr
    原生js的博客
    webstorm调试Node的时候配置
    multiparty
    bluebird
    Nodejs+express+angularjs+mongodb
    mustache.js
    ModelProxy 前端接口配置建模框架
    浏览器跨域访问解决方案
    前端性能优化补充篇
  • 原文地址:https://www.cnblogs.com/quanjun/p/13751276.html
Copyright © 2011-2022 走看看