BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流
题目链接:
题目大意:有$n$种蔬菜,每种蔬菜有$c_{i}$个,每种蔬菜每天有$x_{i}$个单位会坏掉(准确来说每天每种蔬菜坏掉的量是$x_{i}-$当天这种蔬菜卖出量),每卖出一个单位的蔬菜获得收益为$a_{i}$,第一次卖出一种蔬菜会得到$s_{i}$的额外收益,限制每天最多卖出$m$个单位的蔬菜,有$k$次询问,每次询问卖$p_{i}$天的最大收益。
因为每种蔬菜坏掉的部分是固定的,那么我们可以将每种蔬菜分成$\frac{c_{i}-1}{x_{i}}+1$类,第$i$类在第$i$天坏掉。那么对于本题就可以建出费用流模型:源点向每一天连边,容量为$m$,费用为$0$;第$i$天向第$i+1$天连边,容量为$INF$,费用为$0$;每一天向每种蔬菜这一天坏掉的那类连边,容量为这一类的数量,费用为$0$;每一类蔬菜向汇点连边,容量为这一类的数量,费用为$a_{i}$。最后在最后一天每一种蔬菜中取出一个容量新建一个点连向汇点,容量为$1$,费用为$a_{i}+s_{i}$。这样直接跑费用流会有$60pts$。我们观察一下这个图的特殊性质:只有蔬菜向汇点连的边有费用。因为每次增广一定是选取最长路,那么每次增广的路径就一定不会走有费用的反向边(即不会退流)。这也就说明对于$p=i$时选取的蔬菜一定是$p=i-1$时选取的蔬菜的父集(多选的那部分就是最便宜的那$m$个蔬菜)。那么我们可以模拟这个费用流的过程——每次选择当前能选的蔬菜中权值最大的。为了使当前的选择是可行的,设$f[i]$为在第$i$天及之前过期的蔬菜选取量,那么我们就要保证$\forall i,f[i]-i*m<=0$,即$max(f[i]-i*m)<=0$,这个东西我们用线段树来维护即可。那么我们现在的问题就是如何要让当前权值最大的蔬菜尽可能的多选,因为选择第$i$天过期的蔬菜会将所有$i\le j$的$f[j]$都$+1$。那么如果不能选后过期的就一定不能选先过期的,而不能选先过期的可能还能选后过期的,所以我们每次贪心地先选后过期的那部分。如果一次选择使$masx(f[i]-i*m)>0$,说明这种蔬菜剩下的都过期了,那么就撤销这次操作并在以后都不选这种蔬菜。那么我们只要用堆维护所有种类的蔬菜然后从第一天开始,每天贪心地选$m$个蔬菜并记录每天的答案在最后统一输出即可。特别注意$x_{i}=0$的蔬菜看作都在最后一天过期。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define pr pair<int,int>
#define lim 100010
using namespace std;
int c[100010];
int a[100010];
int s[100010];
int x[100010];
int n,m,k,z;
ll ans[100020];
priority_queue<pr>q;
int mx[400010];
int sum[400010];
ll res;
void pushup(int rt)
{
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void pushdown(int rt)
{
if(sum[rt])
{
sum[rt<<1]+=sum[rt];
sum[rt<<1|1]+=sum[rt];
mx[rt<<1]+=sum[rt];
mx[rt<<1|1]+=sum[rt];
sum[rt]=0;
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
mx[rt]=-l*m;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void change(int rt,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
mx[rt]+=v;
sum[rt]+=v;
return ;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)
{
change(rt<<1,l,mid,L,R,v);
}
if(R>mid)
{
change(rt<<1|1,mid+1,r,L,R,v);
}
pushup(rt);
}
bool judge(int id)
{
int t=x[id]?(c[id]-1)/x[id]+1:lim;
change(1,1,lim,t,lim,1);
if(mx[1]<=0)
{
return 1;
}
change(1,1,lim,t,lim,-1);
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i],&s[i],&c[i],&x[i]);
q.push(make_pair(a[i]+s[i],i));
}
build(1,1,lim);
for(int i=1;i<=lim;i++)
{
int num=m;
while(num&&!q.empty())
{
int v=q.top().first;
int id=q.top().second;
q.pop();
if(!judge(id))continue;
res+=v,num--,c[id]--;
if(c[id])
{
q.push(make_pair(a[id],id));
}
}
ans[i]=res;
}
while(k--)
{
scanf("%d",&z);
printf("%lld\n",ans[z]);
}
}
BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流的更多相关文章
- 【BZOJ3252】攻略 DFS序+线段树(模拟费用流)
[BZOJ3252]攻略 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛> ...
- BZOJ4977[Lydsy1708月赛]跳伞求生——贪心+堆+模拟费用流
题目链接: 跳伞求生 可以将题目转化成数轴上有$n$个人和$m$个房子,坐标分别为$a_{i}$和$b_{i}$,每个人可以进一个他左边的房子,每个房子只能进一个人.每个房子有一个收益$c_{i}$, ...
- [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
题目链接: [UOJ455]雪灾与外卖 题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c ...
- BZOJ4946 NOI2017蔬菜(贪心+堆)
容易想到一个费用流做法:将每种蔬菜拆成p种,对应p个过期时间,每一种向可以卖的时间连边,第一次卖的奖励算在最晚过期的一种里.对于天数动态加点.不过这样边数太多了,因为第i天能卖的第i-1天一定能卖,可 ...
- 模拟费用流 & 可撤销贪心
1. CF730I Olympiad in Programming and Sports 大意: $n$个人, 第$i$个人编程能力$a_i$, 运动能力$b_i$, 要选出$p$个组成编程队, $s ...
- 【CF280D】 k-Maximum Subsequence Sum ,线段树模拟费用流
昨天考试被教育了一波.为了学习一下\(T3\)的科技,我就找到了这个远古时期的\(cf\)题(虽然最后\(T3\)还是不会写吧\(QAQ\)) 顾名思义,这个题目其实可以建成一个费用流的模型.我们用流 ...
- Codeforces 280D k-Maximum Subsequence Sum [模拟费用流,线段树]
洛谷 Codeforces bzoj1,bzoj2 这可真是一道n倍经验题呢-- 思路 我首先想到了DP,然后矩阵,然后线段树,然后T飞-- 搜了题解之后发现是模拟费用流. 直接维护选k个子段时的最优 ...
- 【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)
[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交 ...
- 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
随机推荐
- mybatis源码-原来resultMap解析完是这样
目录 1 两个基础类 1.1 列映射类ResultMapping 1.2 结果集映射类ResultMap 2. 解析 2.1 入口函数 2.2 解析流程 2.3 获取 id 2.4 解析结果集的类型 ...
- Linux Docker命令
命令查看你当前的内核版本:uname -r yum 包更新到最新:yum update 安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemap ...
- from bs4 import BeautifulSoup 报错
一: BeautifulSoup的安装: 下载地址:https://www.crummy.com/software/BeautifulSoup/bs4/download/4.6/ 下载后,解压缩,然后 ...
- kattis Programming Tutors 给游客与导游匹配(二分+二分图)
题目来源:https://vjudge.net/problem/Kattis-programmingtutors 题意: 有n个游客,n个导游,给出他们的坐标,问你怎么匹配可以使他们最大距离最小 题解 ...
- js总结:对于字符串的切割截取和合并
1.函数:split() 功能:使用一个指定的分隔符把一个字符串分割存储到数组 例子: str=”jpg|bmp|gif|ico|png”; arr=str.split(”|”); //arr是一个包 ...
- Java对象的创建、内存布局和访问定位
在Java运行时数据区中,我们知道了虚拟机内存的概况,本文介绍虚拟机内存中的数据的其它细节,如对象如何创建.如何布局以及如何访问. 基于实用的原则,这里以HotSpot虚拟机和常用的内存区域Java堆 ...
- SpringMVC controller 时间 T
Spring MVC 之 处理Date类型 - carl.zhao的专栏 - CSDN博客https://blog.csdn.net/u012410733/article/details/727730 ...
- Windows激活
最近重新安装了一下系统,我的系统是Windows10.这就出现了一个问题,如果是Windows7系统的话,可以使用网上的破解工具进行破解操作,使之成为永久破解版.但是Windows10系统,网上对于它 ...
- jmeter环境配置
Java 8 安装 正常安装,一路默认就好,记住安装路径,配置环境变量时用得到.默认安装路径:C:\Program Files\Java\jdk1.8.0_91. 安装好之后会有两个文件夹一个是jdk ...
- JS实用小函数 数据是否合法或存在 获取当前日期时间
1.判断数据是否合法或存在 //判断数据是否合法或存在 function isNotNull(data) { if(data === "" || data === undefine ...