P3592 [POI2015]MYJ

区间dp

P3592

\(n\)家洗车店从左往右排成一排,每家店都有一个正整数价格\(p[i]\)。有\(m\)个人要来消费,第\(i\)个人会驶过第\(a[i]\)个开始一直到第\(b[i]\)个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于\(c[i]\),那么这个人就不洗车了。请给每家店指定一个价格,使得所有人花的钱的总和最大。

因为每个人不洗车的当且仅当\([l_i,r_i]\)中最小的\(p[i]>c[i]\),所以有个显然的性质:每个商家价格是\(c[i]\)一定是最优解之一。因此我们可以将\(c[i]\)离散化。

\(f[l][r][i]\)表示区间\([l,r]\)内最小值是\(i\),从满足\(l\le a \le b\le r\)的人中获得的最大收益

枚举区间最小值所在的点\(k\),则满足\(l\le a\le k\)\(k \le b\le r\)的点最小位置就是\(k\),统计出\(c\ge i\)的人有几个

\(f[l][r][i]=\max\limits_{l\le k\le r}\{realc_i\times cnt+\max\limits_{h\ge i}f[l][k-1][h]+\max\limits_{h\ge i}f[k+1][r][h]\}\)

/**
 *@ author:pyyyyyy/guhl37
 *@ bolg:https://www.cnblogs.com/pyyyyyy
 *@ Debug:
**/
#include <bits/stdc++.h>
using namespace std;
const int N = 55, M = 4100, Cc = 510000;
struct node {
	int a, b, c;
} a[M];
int cmp(node x, node y) {
	return x.b == y.b ? x.a < y.a : x.b < y.b ;
}
int f[N][N][M], g[N][N][M], h[N][M];
int p[N][N][M], val[N], C[M], lsh[Cc], Lsh[M], len;
int n, m;
void dfs(int l, int r, int k){
	if(l > r) return ;
	if(!g[l][r][k]){
		for(int i = l; i <= r; ++i) val[i] = Lsh[k];
		return ;
	}
	for(int i = k; i <= len; ++i) 
		if(g[l][r][k] == f[l][r][i]){
			int pos = p[l][r][i];
			val[pos] = Lsh[i];
			dfs(l, pos - 1, i);
			dfs(pos + 1, r, i);
			break;
		}
}
int main() {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	cin >> n >> m;
	for(int i = 1; i <= m; ++i) cin >> a[i].a >> a[i].b >> a[i].c, C[i] = a[i].c;
	sort(a + 1, a + 1 + m, cmp);
	sort(C + 1, C + m + 1);
	len = 0;
	for(int i = 1; i <= m; ++i)
		if(C[i] != C[i - 1]) Lsh[++len] = C[i], lsh[C[i]] = len;
	for(int i = 1; i <= m; ++i) a[i].c = lsh[a[i].c];
	for(int l = n; l >= 1; --l)
		for(int r =l; r <= n; ++r) {
			for(int i = l; i <= r; ++i)
				for(int j = 1; j <= len; ++j)
					h[i][j] = 0;
			for(int i = 1; i <= m && a[i].b <= r; ++i) {
				if(a[i].a < l) continue;
				for(int j = a[i].a; j <= a[i].b; ++j) h[j][a[i].c]++;
			}
			for(int i = l; i <= r; ++i)
				for(int j = len - 1; j >= 1; --j)
					h[i][j] += h[i][j + 1];
			for(int i = l; i <= r; ++i)
				for(int j = len; j >= 1; --j) {
					int tmp = g[l][i - 1][j] + g[i + 1][r][j] + h[i][j] * Lsh[j];
					if(f[l][r][j] < tmp) f[l][r][j] = tmp, p[l][r][j] = i;
					g[l][r][j] = g[l][r][j + 1] > f[l][r][j] ? g[l][r][j + 1] : f[l][r][j];
				}
		}
	cout << g[1][n][1] << '\n';
	dfs(1, n, 1);
	for(int i = 1; i <= n; ++i) cout << val[i] << ' ';
	return 0;
}
posted @ 2020-07-07 16:29  pyyyyyy  阅读(125)  评论(2编辑  收藏  举报