zoukankan      html  css  js  c++  java
  • 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告

    [USACO13OPEN]照片Photo

    题目描述

    农夫约翰决定给站在一条线上的(N(1 le N le 200,000))头奶牛制作一张全家福照片,(N)头奶牛编号(1)(N)

    于是约翰拍摄了(M(1 le M le 100,000))张照片,每张照片都覆盖了连续一段奶牛:第(i)张照片中包含了编号(a_i)(b_i)的奶牛。但是这些照片不一定把每一只奶牛都拍了进去。

    在拍完照片后,约翰发现了一个有趣的事情:每张照片中都有且仅有一只身上带有斑点的奶牛。约翰意识到他的牛群中有一些斑点奶牛,但他从来没有统计过它们的数量。 根据照片,请你帮约翰估算在他的牛群中最多可能有多少只斑点奶牛。如果无解,输出“(-1)”。

    输入输出格式

    输入格式:

    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.


    我最开始的思路是:

    把区间完全覆盖仅一个区间的删去,把区间完全覆盖大于两个不相交区间的情况算无解。然后剩下区间个数+空余位置即是答案。

    删区间我是按照长度排序从小到大做,然后用树套树维护偏序关系,但发现不相交很难判。。


    题解思路(1):差分约束

    虽然这个题卡差分约束,但我不应该没想到的,应当警醒。

    让每个位置代表这个位置之前有多少头牛,有向边方向为大于等于,连好边了跑最短路就可以了。


    解题思路(2)(dp)

    (dp)的思路很妙,我最开始想过一会儿(dp),但是始终无法直接通过区间来划分状态进行转移。

    考虑对位置进行(dp),规定(dp_i)表示位置(i)强制放牛的最大牛数量。

    考虑某位置(i)强制选后可以转移的区间,设(L_i)(R_i)为转移的两个区间

    (R_i)为覆盖这个点的所以区间的最左左端点(-1)

    (L_i)为区间右端点在这个点(i)左边的区间的最右左端点

    以上两个东西仔细想想应该不难想明白,求法也不难,就是先打好位置标记,然后扫描前缀或后缀最大值。

    转移有

    [dp_i=max_{L_ile j le R_i}dp_j+1 ]

    用一个单调队列维护或者线段树都行(很显然转移区间有单调性)

    这里强调一种写法,因为我们要找到最后一个强制放的位置,所以要枚举答案,但是还要判一下会不会无解,不太好弄。

    不如搞一个虚的(n+1)的位置,最后答案就在(n+1)

    Code:

    #include <cstdio>
    const int N=2e5+10;
    int dp[N],L[N],R[N],n,m,q[N],l,r;
    int max(int x,int y){return x>y?x:y;}
    int min(int x,int y){return x<y?x:y;}
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n+1;i++) R[i]=i-1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&l,&r);
            L[r+1]=max(L[r+1],l);
            R[r]=min(R[r],l-1);
        }
        l=r=0;
        for(int i=1;i<=n+1;i++) L[i]=max(L[i-1],L[i]);
        for(int i=n;i;i--) R[i]=min(R[i+1],R[i]);
        for(int i=1;i<=n+1;i++)
        {
            while(l<=r&&L[i]>q[l]) l++;
            for(int j=max(L[i],q[r]+1);j<=R[i];j++)
            {
                while(l<=r&&dp[j]>=dp[q[r]]) r--;
                q[++r]=j;
            }
            if(l<=r) dp[i]=~dp[q[l]]?dp[q[l]]+1:-1;
            else dp[i]=-1;
        }
        printf("%d
    ",~dp[n+1]?dp[n+1]-1:-1);
        return 0;
    }
    

    2018.10.22

  • 相关阅读:
    小记---------sparkRDD的Transformation 和 Action 及案例 原理解释
    小记---------maxwell启动闪退问题
    小记---------spark组件与其他组件的比较 spark/mapreduce ;spark sql/hive ; spark streaming/storm
    kettle 创建作业发送邮件
    oracle查询表的结构
    ETL简介
    Oracle中分析函数
    谷歌浏览器快捷键
    Kettle入门
    Oracle基本知识
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9834429.html
Copyright © 2011-2022 走看看