【BZOJ】4380: [POI2015]Myjnie

题解

区间dp,先离散化所有价值

\(f[i][j][k]\)表示\([i,j]\)区间里最小值为\(k\)的价值最大是多少

只考虑\(i <= a <= b <= j\)的区间,枚举中间点\(h\),然后如果这个区间包括h就统计在内
\(f[i][j][k] = max(f[i][h - 1][ >=k] + cost(k) + f[h + 1][j][>=k])\)
构造答案的时候通过记录每个点前一个转移点来递归即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 500005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 + c - '0';
	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
	out(x / 10);
    }
    putchar('0' + x % 10);
}
int N,M;
int id[500005],val[4005],tot,ans[55];
int a[4005],b[4005],c[4005],cnt[4005][55];
int f[55][55][4005],g[55][55][4005],pre[55][55][4005];
vector<int> p[55][55];
void dfs(int l,int r,int v,int t = 1) {
    if(l > r) return;
    for(int k = t ; k <= tot ; ++k) {
	if(f[l][r][k] == v) {
	    if(l == r) {ans[l] = val[k];return;}
	    int p = pre[l][r][k];
	    if(!p) {
		for(int i = l ; i <= r ; ++i) ans[i] = val[k];
		return;
	    }
	    ans[p] = val[k];
	    dfs(l,p - 1,g[l][p - 1][k],k);dfs(p + 1,r,g[p + 1][r][k],k);
	    return;
	}
    }
}
void Init() {
    read(N);read(M);
    for(int i = 1 ; i <= M ; ++i) {
	read(a[i]);read(b[i]);read(c[i]);
	val[i] = c[i];
	for(int k = 1 ; k <= N ; ++k) {
	    for(int h = k ; h <= N ; ++h) {
		if(a[i] >= k && b[i] <= h) p[k][h].pb(i);
	    }
	}
    }
    sort(val + 1,val + M + 1);
    tot = unique(val + 1,val + M + 1) - val - 1;
    for(int i = 1 ; i <= tot ; ++i) {
	id[val[i]] = i;
    }
}
void Solve() {
    for(int d = 1 ; d <= N ; ++d) {
	for(int i = 1 ; i <= N ; ++i) {
	    int j = i + d - 1;
	    if(j > N) break;
	    memset(cnt,0,sizeof(cnt));
	    int s = p[i][j].size();
	    for(int k = 0 ; k < s ; ++k) {
		int t = p[i][j][k];
		cnt[id[c[t]]][a[t]]++;cnt[id[c[t]]][b[t] + 1]--;
	    }
	    for(int k = tot ; k >= 1 ; --k) {
		for(int h = i ; h <= j ; ++h) cnt[k][h] += cnt[k][h - 1];
		for(int h = i ; h <= j ; ++h) cnt[k][h] += cnt[k + 1][h];
	    }
	    for(int k = tot ; k >= 1 ; --k) {
		for(int h = i ; h <= j ; ++h) {
		    if(f[i][j][k] < cnt[k][h] * val[k] + g[i][h - 1][k] + g[h + 1][j][k]) {
			pre[i][j][k] = h;
			f[i][j][k] = cnt[k][h] * val[k] + g[i][h - 1][k] + g[h + 1][j][k];
		    }
		}
		g[i][j][k] = max(g[i][j][k + 1],f[i][j][k]);
	    }
	}
    }
    int r = 0;
    for(int i = 1 ; i <= tot ; ++i) r = max(r,f[1][N][i]);
    out(r);enter;
    dfs(1,N,r);
    for(int i = 1 ; i <= N ; ++i) {
	out(ans[i]);
	i == N ? enter : space;
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
    return 0;
}
posted @ 2018-12-12 14:21  sigongzi  阅读(259)  评论(0编辑  收藏  举报