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. openpyxl基本操作

    参考资料:OpenPyXL的使用教程(一) openpyxl 基本操作 # 创建xml from openpyxl import Workbook # 创建工作簿 wb = Workbook() # ...

  2. vue-property-decorator和typescript结合构建的class类组件,父组件触发子组件方法的方式

    vue-property-decorator和typescript结合构建的class类组件,父组件触发子组件方法的方式 class类组件示例 Father类组件 <template> & ...

  3. TopCoder12808 「SRM594Medium」FoxAndGo3 二分图最大独立集

    问题描述 一个 \(N \times N\) 围棋棋盘,任意两个白子不相邻,你要加入若干个黑子并提出白子,最大化空格数目. submit 题解 显然最终棋盘的局面不能够一个白子和它周围的空格都是空的, ...

  4. PHP捕获异常register_shutdown_function和error_get_last的使用

    register_shutdown_function 注册一个会在php中止时执行的函数,注册一个 callback ,它会在脚本执行完成或者 exit() 后被调用. error_get_last ...

  5. idea 出现Can't load AMD 64-bit .dll on a IA 32-bit platform错误

    这个错误是在说无法在IA 32位平台上加载AMD 64位.dll,解决方法如下 下载安装64位的jdk(方法和安装32位的一致,可百度查阅相关资料) 按如下步骤配置

  6. Electron桌面项目-解决throw new Error('Electron failed to install correctly, please delete node_modules..

    前言 Electron 是一个用 HTML,CSS 和 JavaScript 来构建跨平台桌面应用程序的一个开源库.由GitHub开发的. 其原理是 Electron 通过将 Chromium 和 N ...

  7. 每日一题LeetCode 8. 字符串转换整数 (atoi)

    问题描述 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们寻找到的第一个非空字符为正或者负号时,则将 ...

  8. Add an Action with Option Selection 添加具有选项选择的按钮

    In this lesson, you will learn how to create an Action with support for option selection. A new View ...

  9. 高强度学习训练第十六天总结: Spring框架中的设计模式

    仔细想了想..没必要重复造轮子. 每天复习啥了就直接CTRL CV了 https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/system-de ...

  10. Android8.1 开关VOLTE流程分析

    前言 最近有需求需要实现插卡默认打开Volte功能,顺带研究了下Volte的流程,在此做个记录 开始 从Settings设置界面入手,网络和互联网-->移动网络-->VoLTE高清通话(电 ...