Paint题解 DP+二分

Description

You are painting a fence with n sections, numbered from 1 to n. There are k artists, each willing to paint their design on a specific portion of the fence. However, artists will never agree to have their section painted over, so they will only paint their portion of the fence if no one else will paint 
any part of it. 
You want to select a set of painters that does not conflict to minimize the number of unpainted sections.

Input

The first line contains two positive integers n(1≤n≤1018)n(1≤n≤1018) and k(1≤k≤200,000)k(1≤k≤200,000). 
Each of the next kk lines contains two positive integers aiai and bibi, where 1≤ai≤bi≤n1≤ai≤bi≤n, indicating that the iith artist wants to paint all sections between section ai and section bibi, inclusive.

Output

Print, on a single line, a single integer indicating the minimum number of unpainted sections.

Sample Input

8 3
1 3
2 6
5 8

Sample Output

1


Translation

题目给定k个在[1,n]范围内的闭区间,求一个不重叠区间的组合,使得覆盖长度最大。输出这个最大长度。

Solution

①按右端点排序,dp[i]保存考虑前i个区间时的最大覆盖长度。
②求dp[i]时二分找到最后一个不与i重叠的区间j,dp[i]=dp[j]+length[i+1]。
原因:按右端点排序,j之前的肯定不会和i重叠。

 

#include <iostream>
#include <cstring> 
#include <algorithm>
using namespace std;

struct Seg
{
    long long low, high;
    friend bool operator < (const Seg a, const Seg& b)	//按右端点排序 
    {
        if(a.high != b.high) return a.high < b.high;
        return a.low < b.low;
    }
};

bool cmp(const Seg& a, const Seg& b)	//不重叠 
{
    return a.high < b.low;
}

Seg seg[200005];
long long dp[200005];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    long long n, k;
    cin >> n >> k;

    memset(seg, 0, sizeof(seg));

    for(int i = 1; i <= k; ++i)
        cin >> seg[i].low >> seg[i].high;
    sort(seg, seg + k + 1);					//seg[0]保存的都是0,简化边界 

    for(int i = 1; i <= k; ++i)
    {
        int j = lower_bound(seg, seg + i, seg[i], cmp) - seg - 1;	//最后一个不重叠区间 
        dp[i] = dp[j] + seg[i].high - seg[i].low + 1;
        if(dp[i] < dp[i - 1]) dp[i] = dp[i - 1];
    }

    cout << n - dp[k];
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值