题目描述
有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]。有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了。请给每家店指定一个价格,使得所有人花的钱的总和最大。
输入输出格式
输入格式:
第一行包含两个正整数n,m(1<=n<=50,1<=m<=4000)。接下来m行,每行包含三个正整数a[i],b[i],ci
输出格式:
第一行输出一个正整数,即消费总额的最大值。第二行输出n个正整数,依次表示每家洗车店的价格p[i],要求1<=p[i]<=500000。若有多组最优解,输出任意一组。
输入输出样例
说明
有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]。
有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了。
请给每家店指定一个价格,使得所有人花的钱的总和最大。
这题在雅礼讲过,自己还想那么久,太菜了……
对于这道题n=50那就是复杂度是次要的,有做法基本就能过。
我们思考一个区间DP,用dp[l][r][k]表示处理完l, r区间内最小值为k的最大盈利。实际上我们通过限制转移顺序就可以转移这个比较科学的状态了。我们只要在每次只处理:要选择的区间在当前枚举的l, r内的顾客,转移就好办了。但是这样复杂度不够优,我们可以记最小值大于等于k的最大盈利,这样时间复杂度为O(n^3*m),还是略卡。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define For(i, a, b) for(register int i = a; i <= b; ++i)
#define Down(i, a, b) for(register int i = a; i >= b; --i)
using namespace std;
const int maxn = 55, maxm = 4e3 + 5;
int dp[maxn][maxn][maxm], mx[maxn][maxn][maxm], n, m;
int c[maxm], tmp[maxm], rk[maxm], l, r, tot[maxn], tp;
int frm[maxn][maxn][maxm], pi, ans;
struct Q {
int l, r, c;
bool operator <(const Q &A) const {
return c < A.c;
}
}qs[maxm];
void CG(int x) {
For(i, qs[x].l, qs[x].r) ++tot[i];
}
int ret[maxn];
void prt(int l, int r, int k) {
if(l > r) return ;
int mid = dp[l][r][k];
prt(l, mid - 1, frm[l][mid - 1][k]);
ret[mid] = tmp[k];
prt(mid + 1, r, frm[mid + 1][r][k]);
}
int main() {
scanf("%d%d", &n, &m);
For(i, 1, m) {
scanf("%d%d%d", &qs[i].l, &qs[i].r, &qs[i].c);
tmp[i] = qs[i].c;
}
sort(tmp + 1, tmp + m + 1);
For(i, 1, m) if(tmp[i] != tmp[i - 1])
rk[i] = rk[i - 1] + 1; else rk[i] = rk[i - 1];
sort(qs + 1, qs + m + 1);
For(i, 1, m) qs[i].c = rk[i];
tmp[0] = unique(tmp + 1, tmp + m + 1) - tmp - 1;
tp = m;
For(len, 0, n - 1) {
For(x, 1, n - len) {
l = x, r = x + len, tp = m;
memset(tot, 0, sizeof(tot));
Down(i, tmp[0], 1) {
while(qs[tp].c == i){
if(qs[tp].l >= l && qs[tp].r <= r) CG(tp);
--tp;
}
pi = 0, ans = 0;
For(mid, l, r)
if(ans <= mx[l][mid - 1][i] + mx[mid + 1][r][i] + tmp[i] * tot[mid])
pi = mid, ans = mx[l][mid - 1][i] + mx[mid + 1][r][i] + tmp[i] * tot[mid];
mx[l][r][i] = mx[l][r][i + 1];
dp[l][r][i] = pi;
frm[l][r][i] = frm[l][r][i + 1];
if(mx[l][r][i] <= ans) mx[l][r][i] = ans, frm[l][r][i] = i;
}
}
}
printf("%d\n", mx[1][n][1]);
prt(1, n, frm[1][n][1]);
For(i, 1, n) printf("%d ", ret[i]);
return 0;
}
rockdu
没有帐号? 立即注册