围栏

有N块木板从左到右排成一行,有M个工匠对这些木板进行粉刷,每块木板至多被粉刷一次。

第 i 个木匠要么不粉刷,要么粉刷包含木板 Si 的,长度不超过 Li 的连续的一段木板,每粉刷一块可以得到 Pi 的报酬。

不同工匠的Si不同。

请问如何安排能使工匠们获得的总报酬最多。

输入格式
第一行包含两个整数N和M。

接下来M行,每行包含三个整数Li,Pi,Si。

输出格式
输出一个整数,表示结果。

数据范围
1≤N≤16000,
1≤M≤100,
1≤Pi≤10000

输入样例:
8 4
3 2 2
3 2 3
3 3 5
1 1 7 
输出样例:
17
#include<bits/stdc++.h>

#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
const int N = 16e3 + 10, M = 105;
int f[M][N];

struct rec {
    int l, p, s;

    bool operator<(const rec w) const {
        return s < w.s;
    }
} a[M];

int n, m;
deque<pii > q;

inline int calc(int i, int k) {
    return f[i - 1][k] - k * a[i].p;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
        scanf("%d%d%d", &a[i].l, &a[i].p, &a[i].s);
    sort(a + 1, a + 1 + m);
    for (int i = 1; i <= m; i++) {
        q.clear();
        for (int k = max(0, a[i].s - a[i].l); k <= a[i].s - 1; k++) {
            int res = calc(i, k);
            while (!q.empty() && q.back().se <= res)q.pop_back();
            q.emplace_back(k, res);
        }
        for (int j = 1; j <= n; j++) {
            f[i][j] = max(f[i][j - 1], f[i - 1][j]);
            if (j >= a[i].s && j <= min(a[i].s + a[i].l - 1, n)) {
                while (!q.empty() && q.front().fi < j - a[i].l)q.pop_front();
                if (!q.empty())f[i][j] = max(f[i][j], q.front().se + a[i].p * j);
            }
        }
    }
    printf("%d\n", f[m][n]);
    return 0;
}
发布了329 篇原创文章 · 获赞 28 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45323960/article/details/104969612