1. 程式人生 > >BZOJ 4380 [POI2015]Myjnie | DP

BZOJ 4380 [POI2015]Myjnie | DP

要求 兩個 正整數 復雜 play == 便宜 一個 using

鏈接

BZOJ 4380

題面

有n家洗車店從左往右排成一排,每家店都有一個正整數價格p[i]。
有m個人要來消費,第i個人會駛過第a[i]個開始一直到第b[i]個洗車店,且會選擇這些店中最便宜的一個進行一次消費。但是如果這個最便宜的價格大於c[i],那麽這個人就不洗車了。
請給每家店指定一個價格,使得所有人花的錢的總和最大。

Input
第一行包含兩個正整數n,m(1<=n<=50,1<=m<=4000)。
接下來m行,每行包含三個正整數a[i],b[i],ci

Output
第一行輸出一個正整數,即消費總額的最大值。
第二行輸出n個正整數,依次表示每家洗車店的價格p[i],要求1<=p[i]<=500000。

若有多組最優解,輸出任意一組。

題解

這道題……是一個正常的(?)區間DP。

先將所有c[i]離散化。

f[i][j][k]表示區間[i, j]內的店、最低價格為k,能取到的最大價值。這個最大價值包括所有“完全包含在[i, j]”內的顧客提供的價值。

g[i][j][k]表示區間[i, j]內的店、最低價格>=k,能取到的最大價值。

轉移的時候,枚舉最低價格k所在的位置p,采取類似分治的思想,設完全包含在[i, j]內、橫跨位置p、且c[i] >= k的顧客有cnt[p][k]個,那麽有:
\[f[i][j][k] = max_{p = i}^{j} g[i][p - 1][k] + g[p + 1][j][k] + k * cnt[p][k]\]

這個cnt數組在每次枚舉[i, j]的時候都預處理一下。

因為要輸出方案,所以額外記錄一下最優解都是在哪裏取到的,最後dfs求出方案。

總復雜度是\(O(n^3m)\)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define enter putchar('\n')
#define space putchar(' ')
template
<class T> void read(T &x){ char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x){ if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 52, M = 4002; int n, m, a[M], b[M], c[M], cnt[N][M], ans[N], lst[M], idx, f[N][N][M], g[N][N][M], gk[N][N][M]; short fp[N][N][M]; void dfs(int l, int r, int k){ int val = gk[l][r][k], pos = fp[l][r][val]; ans[pos] = lst[val]; if(pos > l) dfs(l, pos - 1, val); if(pos < r) dfs(pos + 1, r, val); } int main(){ read(n), read(m); for(int i = 1; i <= m; i++) read(a[i]), read(b[i]), read(c[i]), lst[i] = c[i]; sort(lst + 1, lst + m + 1); idx = unique(lst + 1, lst + m + 1) - lst - 1; for(int i = 1; i <= m; i++) c[i] = lower_bound(lst + 1, lst + idx + 1, c[i]) - lst; for(int i = n; i; i--) for(int j = i; j <= n; j++){ for(int k = 1; k <= idx; k++) for(int h = i; h <= j; h++) cnt[h][k] = 0; for(int k = 1; k <= m; k++) for(int h = i; h <= j; h++) if(a[k] >= i && a[k] <= h && b[k] >= h && b[k] <= j) cnt[h][c[k]]++; for(int h = i; h <= j; h++) for(int k = idx; k; k--) cnt[h][k] += cnt[h][k + 1]; for(int k = 1; k <= idx; k++) for(int p = i; p <= j; p++) if(g[i][p - 1][k] + g[p + 1][j][k] + lst[k] * cnt[p][k] >= f[i][j][k]) fp[i][j][k] = p, f[i][j][k] = g[i][p - 1][k] + g[p + 1][j][k] + lst[k] * cnt[p][k]; for(int k = idx; k; k--){ if(g[i][j][k + 1] > f[i][j][k]) gk[i][j][k] = gk[i][j][k + 1], g[i][j][k] = g[i][j][k + 1]; else gk[i][j][k] = k, g[i][j][k] = f[i][j][k]; } } write(g[1][n][1]), enter; dfs(1, n, 1); for(int i = 1; i <= n; i++) write(ans[i]), i == n ? enter: space; return 0; }

BZOJ 4380 [POI2015]Myjnie | DP