洛谷P1868 饥饿的奶牛

题目描述

有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字。

现用汉语翻译为:

有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧草。你可以选择任意区间但不能有重复的部分。

对于奶牛来说,自然是吃的越多越好,然而奶牛智商有限,现在请你帮助他。

输入输出格式

输入格式:

第一行,N,如题

接下来N行,每行一个数x,y,如题

输出格式:

一个数,最多的区间数

输入输出样例

输入样例#1:
3
1 3
7 8
3 4
输出样例#1:
5

说明

1<=n<=150000

0<=x<=y<=3000000

分析:线段覆盖的题一般来说都可以用dp做,而且方式就那么几个.一种是长度特别大,线段非常少的,而且线段数量有限制,例如:传送门,这个时候只能用线段作为状态.这道题线段和长度都非常大,只能有一维,如果设线段的话,我不知道是否和前一个线段重叠,不好处理,那么只能设坐标为状态。那么设f[i]表示1~i中能覆盖到的最多的点的个数,先把线段按照右端点排序,如果当前枚举到的这个点正好位于线段内,那么这个线段不能覆盖,那么f[i] = max{f[j]}(j < i),否则f[i] = max{f[当前线段的左端点l - 1] + r - l + 1}.当然,你也可以选择不覆盖,那么答案就是我们之前处理好的最大值.这道题和noip2010引水入城有异曲同工之妙.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int n,f[3000010],maxx;

struct node
{
    int x,y;
}a[150010];

bool cmp(node a,node b)
{
    return a.y < b.y;
}

int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    scanf("%d%d",&a[i].x,&a[i].y);
    sort(a + 1, a + 1 + n,cmp);
    for (int i = 1; i <= n; i++)
    {
        for (int j = a[i].y - 1; j >= 0; j--)
        {
            if (!f[j])
            f[j] = maxx;
            else
            break;
        }
        f[a[i].y] = max(maxx,f[a[i].x - 1] + a[i].y - a[i].x + 1);
        maxx = max(maxx,f[a[i].y]);
    }
    printf("%d
",f[a[n].y]);
    
    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7485495.html