Luogu P2570 [ZJOI2010]贪吃的老鼠
Luogu P2570 [ZJOI2010]贪吃的老鼠
题目描述
奶酪店里最近出现了\(m\)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉。奶酪店中一天会生产\(n\)块奶酪,其中第\(i\)块的大小为\(pi\),会在第\(ri\)秒被生产出来,并且必须在第\(di\)秒之前将它吃掉。第j只老鼠吃奶酪的速度为\(sj\),因此如果它单独吃完第i快奶酪所需的时间为\(pi/sj\)。老鼠们吃奶酪的习惯很独特,具体来说:
(1) 在任一时刻,一只老鼠最多可以吃一块奶酪;
(2) 在任一时刻,一块奶酪最多被一只老鼠吃。
由于奶酪的保质期常常很短,为了将它们全部吃掉,老鼠们需要使用一种神奇的魔法来延长奶酪的保质期。将奶酪的保质期延长\(T\)秒是指所有的奶酪的\(di\)变成\(di+T\)。同时,使用魔法的代价很高,因此老鼠们希望找到最小的T使得可以吃掉所有的奶酪。
输入格式:
输入文件的第一行包含一个整数\(K\),表示输入文件中数据的组数。
每组数据的第一行包含两个整数\(n\)和\(m\),分别表示奶酪和老鼠的数量。接下来的\(n\)行每行包含三个整数\(pi,ri,di\)。最后m行每行包含一个整数,表示\(sj。pi,ri,di,sj\)的含义如上文所述。
输出格式:
包含\(K\)行,每行包含一个实数,表示你找到的最小的\(T\)。你的答案和标准答案的绝对误差不应超过\(10−4\)。
数据范围
100%的数据中,\(1≤K≤5,1≤n,m≤30,1≤pi≤10^5, 0 ≤ri<di≤10^7,1≤sj≤10^5。\)
二分答案后跑最大流检验。
首先我们不考虑第\(2\)个限制。先把所有的时间点离散化,假设有\(k\)个时间段,然后我们将每只老鼠拆成\(k\)个点。从源点连到每个点,容量为\(s_i*len\)。第\(i\)只老鼠在这个时间段的吃奶酪上限为\(s_i*len\),所以就满足了第一个限制。每个奶酪与在\(r_i\)到\(d_i\)之间的时间段连边,然后再连向汇点,容量为\(p_i\)。
现在要考虑第\(2\)个限制。大致思路不变,只是我们要进行一些巧妙(根本想不到)的变换。将所有老鼠按\(s\)排序。第\(i\)只老鼠的新的速度为差分\(t_i=s_i-s_{i-1}\)。第\(i\)个老鼠的第\(j\)个时间点与源点之间的边的容量为\(s_i*len*(n-i+1)\)。其他不变。首先所有老鼠在某个时间段的吃奶酪数量总和不变,然后我们考虑对第\(i\)个奶酪,它在某个时间段内被吃的总量上限为\(len*\sum t_i=len*s_n\),也就是速度最快的那只老鼠。所以对于一个最大流,我们也可以构造出一个合法的情况。
代码:
#include<bits/stdc++.h>
#define N 35
#define eps 1e-6
using namespace std;
inline int Get() {
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while('0'<=ch&&ch<='9') {
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x;
}
int n,m;
struct cheese {
int p,r,d;
}ch[N];
int eat[N];
struct road {
int to,nxt;
double flow;
}s[N*N*N*10];
int h[N*N<<1],cnt;
double totflow;
void Init() {
memset(h,0,sizeof(h));
cnt=1;
}
void add(int i,int j,double f) {
s[++cnt]=(road) {j,h[i],f};h[i]=cnt;
s[++cnt]=(road) {i,h[j],0};h[j]=cnt;
}
int S,T;
queue<int>q;
int dis[N*N<<1];
bool vis[N*N<<1];
bool dinic_bfs() {
memset(dis,0x3f,sizeof(dis));
dis[S]=0;
q.push(S);
while(!q.empty()) {
int v=q.front();
q.pop();
vis[v]=0;
for(int i=h[v];i;i=s[i].nxt) {
int to=s[i].to;
if(s[i].flow>eps&&dis[to]>dis[v]+1) {
dis[to]=dis[v]+1;
if(!vis[to]) {
vis[to]=1;
q.push(to);
}
}
}
}
return dis[T]<1e9;
}
double dfs(int v,double maxf) {
if(v==T) return maxf;
double ret=0;
for(int i=h[v];i;i=s[i].nxt) {
int to=s[i].to;
if(s[i].flow>eps&&dis[to]==dis[v]+1) {
double dlt=dfs(to,min(maxf,s[i].flow));
s[i].flow-=dlt;
s[i^1].flow+=dlt;
ret+=dlt;
maxf-=dlt;
if(maxf<eps) break;
}
}
return ret;
}
double dinic() {
double ans=0;
while(dinic_bfs()) {
while(1) {
double tem=dfs(S,1e9);
if(tem<eps) break;
ans+=tem;
}
}
return ans;
}
vector<double>tim;
bool chk(double ans) {
Init();
tim.clear();
for(int i=1;i<=n;i++) {
tim.push_back(ch[i].r);
tim.push_back(ch[i].d+ans);
}
sort(tim.begin(),tim.end());
tim.resize(unique(tim.begin(),tim.end())-tim.begin());
int tot=m*(tim.size()-1);
T=tot+n+1;
int now=0;
for(int i=1;i<=m;i++) {
for(int j=0;j<tim.size()-1;j++) {
now++;
add(S,now,min(totflow,(double)eat[i]*(tim[j+1]-tim[j])*(m-i+1)));
for(int k=1;k<=n;k++)
if(tim[j]+eps>=ch[k].r&&tim[j+1]<=ch[k].d+ans+eps) add(now,tot+k,min(totflow,(double)eat[i]*(tim[j+1]-tim[j])));
}
}
for(int i=1;i<=n;i++) add(tot+i,T,ch[i].p);
double Flow=dinic();
return fabs(Flow-totflow)<eps;
}
int main() {
int cas=Get();
while(cas--) {
n=Get(),m=Get();
totflow=0;
for(int i=1;i<=n;i++) {
ch[i].p=Get();
ch[i].r=Get();
ch[i].d=Get();
totflow+=ch[i].p;
}
for(int i=1;i<=m;i++) eat[i]=Get();
sort(eat+1,eat+1+m);
double mx=eat[m];
for(int i=m;i>=1;i--) eat[i]-=eat[i-1];
double l=0,r=(double)totflow/mx+1,mid;
while(l+eps<r) {
mid=(l+r)/2.0;
if(chk(mid)) r=mid;
else l=mid+eps;
}
cout<<fixed<<setprecision(5)<<l<<"\n";
}
return 0;
}
Luogu P2570 [ZJOI2010]贪吃的老鼠的更多相关文章
- luogu P2570 [ZJOI2010]贪吃的老鼠【二分+最大流】
首先考虑只满足第一个条件,二分答案,把过期时间加上mid之后的2n个时间离散,老鼠拆成每个时间的,第i个时间第j个老鼠为id[i][j],连接(s,i,p[i]),对于离散后时间(g[j-1]~g[j ...
- P2570 [ZJOI2010]贪吃的老鼠
传送门 →_→唯一一篇能看得懂的题解---->这里 很容易想到二分+网络流,然而并没有什么卵用--出题人的思路太神了-- 首先考虑如果一块奶酪在同一时间可以被多只老鼠吃的话,该如何建图.首先不难 ...
- 洛谷$P2570\ [ZJOI2010]$贪吃的老鼠 网络流+二分
正解:网络流+二分 解题报告: 传送门$QwQ$ 和上一题有点儿像,,,?$QwQ$但是比上一题要有趣很多$QwQ$ 首先把大致思路捋下?依然是.二分出每个奶酪的开始和结束时间,然后check下最大流 ...
- Luogu2570 [ZJOI2010]贪吃的老鼠 ---- 网络流
Luogu2570 [ZJOI2010]贪吃的老鼠 题面描述 https://www.luogu.org/problemnew/show/P2570 然后题意大概就是m只老鼠,然后吃n个奶酪,已知 ...
- Luogu2570 ZJOI2010 贪吃的老鼠 二分答案+最大流
题目链接:https://www.luogu.org/problemnew/show/P2570 题意概述: 好像没什么好概述的.....很简洁? 分析: 首先想到二分时间,转化成判定性问题,在一定时 ...
- [ZJOI2010]贪吃的老鼠(网络流+建图)
题目描述 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块奶酪,其中第i块的大小为pi,会在第ri秒被生产出来,并且必须在第di秒之前将它吃掉.第j只老鼠吃 ...
- [ZJOI2010]贪吃的老鼠
很不错的一道网络流的题目 二分答案是显然的 首先不考虑每个饼干只能一个老鼠吃 那很显然的建图就是将时间点按照开始结束的点分成2*n-1段 然后对每一段时间建m个老鼠的点,然后s-它限流,再从它到目前可 ...
- [ZJOI2010]贪吃的老鼠 网络流
---题面--- 题解: 这是一道强题emmmm,做法非常巧妙,,,我也是看了好久大佬题解才看明白一点 首先考虑没有限制的情况,即n个老鼠可以在同一时刻吃同一块奶酪 对各个时间段拆点,连奶酪 ---& ...
- 【题解】ZJOI2010贪吃的老鼠
%%%%真的好强...看题解我都看了好久才完全明白.放一下参考的博客,谢谢神犇QAQ 1号博客 2号博客(超级赞的啦) 因为理解的过程太艰辛,所以必须记录一下这道强题:这道题目最难的两个约束就在 ...
随机推荐
- 如何使用coe_load_sql_profile.sql来固定sql profile
SQLT工具包含一个脚本,名字是 coe_load_sql_profile.sql,下面以用户SCOTT的EMP表为例,说明如何使用该脚本固定sql profile. 1. SQL> -- 对e ...
- [Linux] 多进程网络编程监听一个端口
SO_REUSEPORT支持多个进程或者线程绑定到同一端口 每个进程可以自己创建socket.bind.listen.accept相同的地址和端口,各自是独立平等的.让多进程监听同一个端口,各个进程中 ...
- rpm包安装java jar开机自启
1.安装jdk: rpm -ivh jdk-8u201-linux-x64.rpm 2.配置jdk路径 打开/etc/profile增加以下内容: export JAVA_HOME=/usr/java ...
- github二级域名配置
首先打开GitHub并登上你的GitHub账号 新建仓库 点击settings 接下来就是操作git往这个仓库存文件,该域名会访问index.html文件
- Mysql安装及常用命令
部分内容转载于 https://www.linuxidc.com/Linux/2016-09/135288.htm https://www.cnblogs.com/rays-/p/8081798.ht ...
- mysql 数据误删恢复
当binlog_format设置为ROW时,想查看binlog中的sql语句时,需要解密,添加这个 --base64-output=decode-rows -v
- 缓冲字符流 java.io.BufferedWriter ,java.io.BufferedReader,缓冲字符输出流:PrintWriter
package seday07; import java.io.IOException;import java.io.PrintWriter; /*** @author xingsir * 缓冲字符流 ...
- Python 中運算子 + 與 * 的 Overload 方法重載功能
字串 String 原本不能像數值一樣有加減乘除運算,但有例外.例如: >>> 'Good' + 'Morning''GoodMorning' 運算子 + 可將2個字串,串接起來. ...
- Python计算美国总统的身高并实现数据可视化
代码如下: import numpy as np import pandas as pd import matplotlib.pyplot as plt data=pd.read_csv('presi ...
- scp跨服务器拷贝,后台运行
[转载]原文:https://blog.csdn.net/u013091013/article/details/68941250 通常情况下,我门在同一台服务器拷贝数据最常用的命令便是cp,如果要在不 ...