您的位置:首页 > 其它

BZOJ4380[POI2015] Myjnie

2016-10-14 20:52 302 查看
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

Solution:

神一样的dp…

首先先对c[i]离散。

因为与这道题相关的量是区间的最小值,所以定义dp[i][j][k]表示区间[i,j]的最小值为k的最大值。再将这个dp定义扩展一下:dp[i][j][k]=max(dp[i][j][t],t∈[k,Max])。

所以再记一个pre[i][j][k]表示当前的dp[i][j][k]的”实际k值“,记一个fa[i][j][k]表示当前状态的最小值取在哪个点(用于输出方案)。

转移时:每一次用O(nm)算一个当最小值为k时,最小值在i点,可以消费的顾客数(顾客的区间被大区间完全包含)。转移方程:

dp[i][j][k]=max(cnt[pos][k]+dp[i][pos−1][k]+dp[pos+1][j][k])(pos∈[i,j])

dp[i][j][k]=max(dp[i][j][k],dp[i][j][k+1])(k=Max→0)

然后再根据pre数组和fa数组还原方案即可,复杂度O(n3m)

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 55
#define M 4005
using namespace std;
void Rd(int &res){
char c;res=0;
while(c=getchar(),!isdigit(c));
do{
res=(res<<1)+(res<<3)+(c^48);
}while(c=getchar(),isdigit(c));
}
struct Node{int L,R,w;}A
;
int dp

[M],pre

[M],fa

[M],Ans
,val[M],cnt
[M];
void Pf(int L,int R,int k){
k=pre[L][R][k];
int pos=fa[L][R][k];
Ans[pos]=val[k];
if(pos>L)Pf(L,pos-1,k);
if(pos<R)Pf(pos+1,R,k);
}
int main(){
int n,m;
Rd(n);Rd(m);
for(int i=1;i<=m;i++){
Rd(A[i].L);Rd(A[i].R);Rd(A[i].w);
val[i-1]=A[i].w;
}
sort(val,val+m);
int sz=unique(val,val+m)-val;
for(int i=1;i<=m;i++)
A[i].w=lower_bound(val,val+sz,A[i].w)-val;
sz--;//[0,sz]
for(int L=n;L>=1;L--)
for(int R=L;R<=n;R++){
for(int i=L;i<=R;i++)
for(int j=0;j<=sz;j++)
cnt[i][j]=0;
for(int i=1;i<=m;i++){
if(A[i].L<L||A[i].R>R)continue;
for(int j=A[i].L;j<=A[i].R;j++)
cnt[j][A[i].w]++;
}
for(int i=L;i<=R;i++)
for(int j=sz-1;j>=0;j--)
cnt[i][j]+=cnt[i][j+1];
pre[L][R][sz]=sz;
for(int k=sz;k>=0;k--){
int mx=-1,pos;
for(int i=L;i<=R;i++){
int tmp1=0,tmp2=0;
if(i>L)tmp1=dp[L][i-1][k];
if(i<R)tmp2=dp[i+1][R][k];
int rs=val[k]*cnt[i][k]+tmp1+tmp2;
if(rs>mx)mx=rs,pos=i;
}
dp[L][R][k]=mx;
fa[L][R][k]=pos;
if(k<sz){
if(dp[L][R][k+1]>dp[L][R][k]){
dp[L][R][k]=dp[L][R][k+1];
pre[L][R][k]=pre[L][R][k+1];
}else pre[L][R][k]=k;
}
}
}
printf("%d\n",dp[1]
[0]);
Pf(1,n,0);
for(int i=1;i<=n;i++)
printf("%d%c",Ans[i]," \n"[i==n]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: