• P3084 [USACO13OPEN]照片Photo (dp+单调队列优化)


    题目链接:传送门

    题目:

    题目描述
    
    Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always, are conveniently numbered from 1..N. Accordingly, he snapped M (1 <= M <= 100,000) photos, each covering a contiguous range of cows: photo i contains cows a_i through b_i inclusive. The photos collectively may not necessarily cover every single cow.
    
    After taking his photos, FJ notices a very interesting phenomenon: each photo he took contains exactly one cow with spots! FJ was aware that he had some number of spotted cows in his herd, but he had never actually counted them. Based on his photos, please determine the maximum possible number of spotted cows that could exist in his herd. Output -1 if there is no possible assignment of spots to cows consistent with FJ's photographic results.
    
    输入输出格式
    输入格式:
    
    * Line 1: Two integers N and M.
    
    * Lines 2..M+1: Line i+1 contains a_i and b_i.
    
    输出格式:
    
    * Line 1: The maximum possible number of spotted cows on FJ's farm, or -1 if there is no possible solution.
    
    输入输出样例
    输入样例#15 3 
    1 4 
    2 5 
    3 4 
    
    输出样例#11 
    
    说明
    
    There are 5 cows and 3 photos. The first photo contains cows 1 through 4, etc.
    
    From the last photo, we know that either cow 3 or cow 4 must be spotted. By choosing either of these, we satisfy the first two photos as well.
    View Code

    思路:

      如果要把牛放在第i个位置,它之前的那只牛应该放在[li, ri]之间,根据输入处理出li和ri,就可以转移状态了。

      读入x,y时,用x更新ly+1,用x-1更新ry。

      读入结束之后从前往后扫一遍,用li-1更新li;再从后往前扫一遍,用ri+1更新ri。

      然后就可以跑dp了,f[i] = max{f[j] | li ≤ j ≤ ri}

    状态:

      f[i] 表示把最后一只牛放在第i个位置的最大数量。

    状态转移方程:

      f[i] = max{f[j] | li ≤ j ≤ ri}

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAX_N = 2e5 + 5;
    #define tomax(a, b) a = a>b?a:b
    #define tomin(a, b) a = a<b?a:b
    
    int N, M, l[MAX_N], r[MAX_N];
    int f[MAX_N];
    
    int main()
    {
    //    freopen("testdata.in", "r", stdin);
        cin >> N >> M;
        for (int i = 1; i <= N+1; i++)
            r[i] = i-1;
        for (int i = 1; i <= M; i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            tomin(r[y], x-1);
            tomax(l[y+1], x);
        }
        for (int i = 2; i <= N+1; i++)
            tomax(l[i], l[i-1]);
        for (int i = N; i >= 1; i--)
            tomin(r[i], r[i+1]);
        memset(f, -1, sizeof f);
        f[0] = 0;
        for (int i = 1; i <= N+1; i++)
            for (int j = l[i]; j <= r[i]; j++) if(f[j] != -1)
                tomax(f[i], f[j] + (i!=N+1 ? 1 : 0));
    
        cout << f[N+1] << endl;
        return 0;
    }
    /*
    5 3
    1 4
    2 4
    1 1
    */
    View Code

    本来是瞄了一眼题解,理解了思路之后准备不优化暴力T一发的,结果直接AC了,还跑得贼快?-。=

    不过这样子写应该可以被两只牛的大数据卡掉:

    200000 2
    1 100000
    100001 200000
    View Code

    献上单调队列优化的正解:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAX_N = 2e5 + 5;
    #define tomax(a, b) a = a>b?a:b
    #define tomin(a, b) a = a<b?a:b
    
    int N, M, l[MAX_N], r[MAX_N];
    int h, t, q[MAX_N], f[MAX_N];
    
    int main()
    {
        cin >> N >> M;
        memset(f, 0, sizeof f);
        for (int i = 1; i <= N+1; i++)
            r[i] = i-1;
        for (int i = 1; i <= M; i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            tomin(r[y], x-1);
            tomax(l[y+1], x);
        }
        for (int i = 2; i <= N+1; i++)
            tomax(l[i], l[i-1]);
        for (int i = N; i >= 1; i--)
            tomin(r[i], r[i+1]);
        int j = 1;
        h = 1, t = 0, q[++t] = 0;
        for (int i = 1; i <= N+1; i++) {
            while (j <= N && j <= r[i]) {
                if (f[j] == -1) {
                    ++j;
                    continue;
                }
                while (h <= t && f[q[t]] <= f[j]) --t;
                q[++t] = j;
                ++j;
            }
            while (h <= t && q[h] < l[i]) ++h;
            if (h <= t) f[i] = f[q[h]] + (i!=N+1 ? 1 : 0);
            else f[i] = -1;
        }
        cout << f[N+1] << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    iOS 8 界面设计 PSD 模板(iPhone 6),免费下载
    20个华丽的时间轴例子,寻找网页设计灵感
    Hello.js – Web 服务授权的 JavaScript SDK
    Web 开发人员和设计师必读文章推荐【系列三十】
    Arctext.js
    30套免费的响应式 HTML5 & CSS3 模板下载
    Midnight.js – 实现奇妙的固定头部切换效果
    推荐20个很有帮助的 Web 前端开发教程
    SweetAlert – 替代 Alert 的漂亮的提示效果
    其实每个行业都有各自的辛苦,好的程序员并不累,他们乐此不疲(见过太多在职位事业、人生方向上随转如流的人,累了疲乏了就去做别的事情了。必须有自己的坚守和立足的点,自我驱动,否则沦为在别人的体制制度中被驱赶一生)good
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9886372.html
Copyright © 2020-2023  润新知