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]贪吃的老鼠的更多相关文章

  1. luogu P2570 [ZJOI2010]贪吃的老鼠【二分+最大流】

    首先考虑只满足第一个条件,二分答案,把过期时间加上mid之后的2n个时间离散,老鼠拆成每个时间的,第i个时间第j个老鼠为id[i][j],连接(s,i,p[i]),对于离散后时间(g[j-1]~g[j ...

  2. P2570 [ZJOI2010]贪吃的老鼠

    传送门 →_→唯一一篇能看得懂的题解---->这里 很容易想到二分+网络流,然而并没有什么卵用--出题人的思路太神了-- 首先考虑如果一块奶酪在同一时间可以被多只老鼠吃的话,该如何建图.首先不难 ...

  3. 洛谷$P2570\ [ZJOI2010]$贪吃的老鼠 网络流+二分

    正解:网络流+二分 解题报告: 传送门$QwQ$ 和上一题有点儿像,,,?$QwQ$但是比上一题要有趣很多$QwQ$ 首先把大致思路捋下?依然是.二分出每个奶酪的开始和结束时间,然后check下最大流 ...

  4. Luogu2570 [ZJOI2010]贪吃的老鼠 ---- 网络流

    Luogu2570  [ZJOI2010]贪吃的老鼠 题面描述 https://www.luogu.org/problemnew/show/P2570 然后题意大概就是m只老鼠,然后吃n个奶酪,已知 ...

  5. Luogu2570 ZJOI2010 贪吃的老鼠 二分答案+最大流

    题目链接:https://www.luogu.org/problemnew/show/P2570 题意概述: 好像没什么好概述的.....很简洁? 分析: 首先想到二分时间,转化成判定性问题,在一定时 ...

  6. [ZJOI2010]贪吃的老鼠(网络流+建图)

    题目描述 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块奶酪,其中第i块的大小为pi,会在第ri秒被生产出来,并且必须在第di秒之前将它吃掉.第j只老鼠吃 ...

  7. [ZJOI2010]贪吃的老鼠

    很不错的一道网络流的题目 二分答案是显然的 首先不考虑每个饼干只能一个老鼠吃 那很显然的建图就是将时间点按照开始结束的点分成2*n-1段 然后对每一段时间建m个老鼠的点,然后s-它限流,再从它到目前可 ...

  8. [ZJOI2010]贪吃的老鼠 网络流

    ---题面--- 题解: 这是一道强题emmmm,做法非常巧妙,,,我也是看了好久大佬题解才看明白一点 首先考虑没有限制的情况,即n个老鼠可以在同一时刻吃同一块奶酪 对各个时间段拆点,连奶酪 ---& ...

  9. 【题解】ZJOI2010贪吃的老鼠

    %%%%真的好强...看题解我都看了好久才完全明白.放一下参考的博客,谢谢神犇QAQ 1号博客    2号博客(超级赞的啦) 因为理解的过程太艰辛,所以必须记录一下这道强题:这道题目最难的两个约束就在 ...

随机推荐

  1. C#&.Net干货分享- 构造BaiduLanguageHelper对接百度的语言翻译

    全部是封装的API源码... namespace Frame.Api{    /// <summary>    /// 百度多语言支持器    /// </summary>   ...

  2. 011.MongoDB性能监控

    一 MongoDB 监控 1.1 监控概述 MongoDB自带了mongostat 和 mongotop 这两个命令来监控MongoDB的运行情况.这两个命令用于处理MongoDB数据库变慢等等问题非 ...

  3. November 10th, Week 45th, Sunday, 2019

    Perfection has no place in love. 爱从不完美. Perfection has no place in love, and we should always try to ...

  4. web测试点集合

    转自:https://blog.csdn.net/yuki_ying/article/details/54946541 web测试点一 .界面检查 进入一个页面测试,首先是检查title,页面排版,字 ...

  5. 性能分析-java程序篇之案例-工具和方法

    1. 背景说明 线上服务响应时间超过40秒,登录服务器发现cpu将近100%了(如下图),针对此问题,本文说明排查过程.工具以定位具体的原因. 2. 分析排查过程 此类问题的排查,有两款神器可用,分别 ...

  6. Jmeter文件目录介绍

    当我们解压安装包后,在主目录下有以下文件目录,在这里就不一一介绍,主要介绍一些会经常使用到的文件或目录 1.bin目录——存放启动脚本.配置文件.模板等文件 examples:该目录下存放Jmeter ...

  7. sql server报【将截断字符串或二进制数据】错误

    会出现这个错误的原因是因为表设置的列长度小于要插入的数据的长度. 可以从下列的6个方面去排查: 1.表设置的列名长度太短. 2.插入的数据太长. 3.有默认值. 4.有触发器. 5 从char数据类型 ...

  8. 解决NuGet下载太慢的问题

    以下载CefSharp.Wpf v57.0.0版本为例: 1.打开NuGet官网:https://www.nuget.org/ 2.输入CefSharp.Wpf,点击查询,如下所示: 3.确认版本正确 ...

  9. fluwx使用的问题

    今天搞了下fluwx这个库,也是遇到了很多问题. 问题一:‘包名不对,请检查包名是否与开放平台上填写的一致’ 显示把文档这些看了遍,但是也不是很清楚,还加了下群问别人,主要我没有开发过Android, ...

  10. Python 條件式 Condition

    除了重複使用Function,有時我們須檢查結果,依此判斷下個步驟該怎麼進行,如此就需要條件式 condition statement. if ... elif ... ese ( 或 if ... ...