丽娃河的狼人传说

原题:丽娃河的狼人传说

原题大意

丽娃河可以看成是从 1 到 n的一条数轴。为了美观,路灯只能安装在整数点上,每个整数点只能安装一盏路灯。经专业勘测,有m个区间特别容易发生事故,所以至少要安装一定数量的路灯,请问至少还要安装多少路灯。

Input

第一行一个整数 T (1≤T≤300),表示测试数据组数。

对于每组数据:

第一行三个整数 n,m,k (1≤n≤103,1≤m≤103,1≤k≤n)。

第二行 k 个不同的整数用空格隔开,表示这些位置一开始就有路灯。

接下来 m 行表示约束条件。第 i 行三个整数 li,ri,ti 表示:第 i 个区间 [li,ri]少要安装 ti 盏路灯 (1≤li≤ri≤n,1≤ti≤n)。

Output

对于每组数据,输出Casex:y。其中x表示测试数据编号(从1开始),y表示至少要安装的路灯数目。如果无解,y 为 −1。

算法分析

按右端点排序,然后对于不满足条件的尽量往右垒就好了。贪心的证明:由于左边的都已经垒满了,所以垒左边的肯定是没意义的。垒中间肯定没有垒右边的号,因为右边的区间不可能长得断开,使得垒在左边收益更大。这样就可以实现 O(n2)。

程序代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn = 1005;
int T, n, m, k, kase;
int line[maxn], cnt;
struct interval{
    int l, r, req;
    bool friend operator < (interval a, interval b){
        return a.r < b.r;
    }
}inter[maxn];
int main() {

    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> T;
    bool fg = false;
    while(T--){
        mem(line, 0);
        fg = true;
        cnt = 0;
        cin >> n >> m >> k;
        for(int i = 0; i < k; i++){
            int t;
            cin >> t;
            line[t]++; 
        }
        for(int i = 0; i < m; i++){
            cin >> inter[i].l >> inter[i].r >> inter[i].req;

        }
        sort(inter, inter+m);
        for(int i = 0; i < m; i++){
            int res = 0;
            for(int j = inter[i].l; j <= inter[i].r; j++)
                res+=line[j];
            int len = inter[i].r-inter[i].l+1;
            if(len - res  < inter[i].req - res){fg = false; break;}
            int t = inter[i].req - res;
            for(int j = inter[i].r; j >= inter[i].l && t > 0; j--){
                if(line[j] == 0){
                    line[j]++;
                    t--;
                    cnt++;
                }
            }
        }
        if(!fg) cnt = -1;
        cout << "Case " << ++kase << ": " << cnt << endl;
    }
    return 0;
}