标签:lan fence i++ code struct main algo 价值 turn
大意:
有 N 块连续的木板,并有 K 个工人来粉刷,但不要求全部粉刷。每个工人有三个参数:L,P,S,表示其最多粉刷连续的 L 块木板,并且每粉刷一块木板可获得 P 元,但所粉刷的木板必须包括第 S 块。输出所能获得最大价值。
思路:
dp[i][j] 表示第 i 个人粉刷到第 j 块木板,所获得最大价值。
dp[i][j] = max{ dp[i][j-1] , dp[i-1][j] , dp[i-1][k] + (j-k)·p[i] }
分别表示:第 i 个人不刷、第 j 面墙不刷、第 i 个人刷 k+1 到 j 块木板。且对于第三种,需满足 j-l[i]<=k<=s[i]-1 和 s[i]<=j<=s[i]+l[i]-1。
对于第三项来说,需要进行优化,可以发现转化为 dp[i-1][k]+k×p[i] 和 j×P[i] 这两项,后一项是常数,那么只需要单调队列求出前面的最大值即可
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXM = 200;
const int MAXN = 2e5 + 5;
typedef long long LL;
struct node {
int l, p, s;
} a[MAXM];
int n, m, le[MAXM], re[MAXM], q[MAXM], dp[MAXM][MAXN];
bool cmp(const node &a, const node &b) { return a.s < b.s; }
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 + m + 1, cmp);
for (int i = 1; i <= m; i++) {
le[i] = max(0, a[i].s - a[i].l);
re[i] = min(n, a[i].s + a[i].l - 1);
}
for (int i = 1; i <= m; i++) {
int l = a[i].l;
int p = a[i].p;
int s = a[i].s;
for (int j = 0; j <= re[i]; j++)
dp[i][j] = dp[i - 1][j];
int h = 1;
int t = 0;
for (int j = le[i]; j < a[i].s; j++) { //维护单调队列
while (h <= t && dp[i - 1][j] - j * p >= dp[i - 1][q[t]] - q[t] * p)
t--;
q[++t] = j;
}
for (int j = s; j <= re[i]; j++) {
while (h < t && j - q[h] > l) h++;
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
dp[i][j] = max(dp[i][j], dp[i - 1][q[h]] + (j - q[h]) * p);
}
for (int j = re[i] + 1; j <= n; j++)
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
int ans = 0;
for (int i = 1; i <= n; i++) ans = max(ans, dp[m][i]);
printf("%d\n", ans);
return 0;
}
标签:lan fence i++ code struct main algo 价值 turn
原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14535155.html