1. 程式人生 > >【BZOJ4380】[POI2015]Myjnie 區間DP

【BZOJ4380】[POI2015]Myjnie 區間DP

jni () iostream oid 計算 有一個 tchar output return

【BZOJ4380】[POI2015]Myjnie

Description

有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],c[i](1<=a[i]<=b[i]<=n,1<=c[i]<=500000)

Output

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

Sample Input

7 5
1 4 7
3 7 13
5 6 20
6 7 1
1 2 5

Sample Output

43
5 5 13 13 20 20 13

題解:先離散化,然後DP:令f[i][j][k]表示在[i,j]中最小值為k的最大收益。然後轉移時枚舉[i,j]中的最小值l,然後用(f[i][l-1][k..m]+f[l+1][j][k..m]+所有經過l的顧客貢獻)更新f[i][j][k]。那麽如何計算所有經過l的顧客的貢獻呢?我們在枚舉到i和j時,先預處理出g[i][k]表示在當前區間中,經過i且限制條件>=k的顧客的數量。就容易轉移了。

輸出方案時對於DP的每個地方都維護個pre指針即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,M;
int f[55][55][4010],ref[4010],s[55][55][4010],g[55][4010],gp[55][55][4010],sp[55][55][4010],v[55];
struct node
{
	int a,b,c;
}p[4010];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
bool cmp(const node &a,const node &b)	{return a.c<b.c;}
void print(int l,int r,int x)
{
	if(l>r)	return ;
	x=sp[l][r][x];
	int mid=gp[l][r][x];
	v[mid]=ref[x];
	print(l,mid-1,x),print(mid+1,r,x);
}
int main()
{
	n=rd(),m=rd();
	int i,j,k,l;
	for(i=1;i<=m;i++)	p[i].a=rd(),p[i].b=rd(),p[i].c=rd();
	sort(p+1,p+m+1,cmp);
	for(i=1;i<=m;i++)
	{
		if(p[i].c>ref[M])	ref[++M]=p[i].c;
		p[i].c=M;
	}
	//memset(f,-1,sizeof(f));
	for(j=0;j<n;j++)
	{
		for(i=1;i+j<=n;i++)
		{
			memset(g,0,sizeof(g));
			for(k=1;k<=m;k++)	if(p[k].a>=i&&p[k].b<=i+j)
				for(l=p[k].a;l<=p[k].b;l++)	g[l][p[k].c]++;
			for(l=i;l<=i+j;l++)	for(k=M;k>=1;k--)	g[l][k]+=g[l][k+1];
			for(k=M;k>=1;k--)
			{
				for(l=i;l<=i+j;l++)
				{
					if(f[i][i+j][k]<=s[i][l-1][k]+s[l+1][i+j][k]+g[l][k]*ref[k])
					{
						f[i][i+j][k]=s[i][l-1][k]+s[l+1][i+j][k]+g[l][k]*ref[k];
						gp[i][i+j][k]=l;
					}
				}
				if(f[i][i+j][k]>=s[i][i+j][k+1])
					s[i][i+j][k]=f[i][i+j][k],sp[i][i+j][k]=k;
				else
					s[i][i+j][k]=s[i][i+j][k+1],sp[i][i+j][k]=sp[i][i+j][k+1];
			}
		}
	}
	printf("%d\n",s[1][n][1]);
	print(1,n,1);
	for(i=1;i<=n;i++)	printf("%d%c",v[i],i==n?‘\n‘:‘ ‘);
	return 0;
}

【BZOJ4380】[POI2015]Myjnie 區間DP