• 题解【AcWing1090】绿色通道


    题面

    题目要求出最长的空题段最短的长度,显然可以二分答案。

    考虑如何 check。

    设二分到的值是 (x),即最长的空题段长度至少为 (x)

    其实整个 check 的过程可以看作一个 DP,设 (dp_i) 表示 (1sim i) 中 写第 (i) 道题 且 最长的空题段长度 (leq x) 所需的最短时间。

    由于空题段最长为 (x),且区间 ([i-x, i - 1]) 中有 (x) 个点, 所以转移方程不难得出:(dp_i=min_{i-x-1leq j leq i-1}{dp_j} + a_i)

    问题又变成了一个典型的滑动窗口问题,可以使用单调队列优化。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 50003;
    
    int n, m, t, a[N], dp[N], q[N], hh, tt, ans;
    
    inline bool check(int x)
    {
        memset(dp, 0, sizeof dp);
        hh = tt = 0; //队列中预先存储了一个 dp[0] = 0
        for (int i = 1; i <= n; i+=1)
        {
            while (hh <= tt && q[hh] < i - x - 1) ++hh; //队头超出了范围
            dp[i] = dp[q[hh]] + a[i]; //转移
            while (hh <= tt && dp[q[tt]] >= dp[i]) --tt; //维护队列单调性
            q[++tt] = i; //加入队列
        }
        int sum = 2000000007; 
        for (int i = n - x; i <= n; i+=1)
            sum = min(sum, dp[i]); //求出最短的时间
        return sum <= t; //最多只有 t 分钟
    }
    
    int main()
    {
        cin >> n >> t;
        for (int i = 1; i <= n; i+=1) cin >> a[i];
        int l = 0, r = n;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            if (check(mid)) ans = mid, r = mid - 1;
            else l = mid + 1;
        }
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    git merge
    google platform
    http tutorial
    DS,AA tree
    Java,Hashtable
    java,Object
    Pumping lemma for regular languages
    Pumping lemma
    Context-free grammar
    Formal language
  • 原文地址:https://www.cnblogs.com/xsl19/p/12362748.html
Copyright © 2020-2023  润新知