博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ4380】[POI2015]Myjnie 区间DP
阅读量:5071 次
发布时间:2019-06-12

本文共 2164 字,大约阅读时间需要 7 分钟。

【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 
#include
#include
#include
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
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
=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;}

 

转载于:https://www.cnblogs.com/CQzhangyu/p/7707836.html

你可能感兴趣的文章
设置虚拟机虚拟机中fedora上网配置-bridge连接方式(图解)
查看>>
[置顶] Android仿人人客户端(v5.7.1)——人人授权访问界面
查看>>
ES6内置方法find 和 filter的区别在哪
查看>>
Android实现 ScrollView + ListView无滚动条滚动
查看>>
java学习笔记之String类
查看>>
UVA 11082 Matrix Decompressing 矩阵解压(最大流,经典)
查看>>
硬件笔记之Thinkpad T470P更换2K屏幕
查看>>
iOS开发——缩放图片
查看>>
HTTP之URL的快捷方式
查看>>
满世界都是图论
查看>>
配置链路聚合中极小错误——失之毫厘谬以千里
查看>>
蓝桥杯-分小组-java
查看>>
Android Toast
查看>>
iOS开发UI篇—Quartz2D使用(绘制基本图形)
查看>>
docker固定IP地址重启不变
查看>>
桌面图标修复||桌面图标不正常
查看>>
JavaScript基础(四)关于对象及JSON
查看>>
JAVA面试常见问题之Redis篇
查看>>
jdk1.8 api 下载
查看>>
getElement的几中属性介绍
查看>>