problem

luogu-P2570

solution

卧槽网络流尼玛神题

首先这个最小延长时间 TTT ,套路地考虑二分,将问题转化为判定性问题。

其次 n,mn,mn,m 和奶酪存在时间 [l,r][l,r][l,r] 的量级差很大,我们肯定会猜想一段时间内选择吃奶酪的老鼠是一样,套路地考虑离散化。

将 nnn 个奶酪的出现、消失时间放进时间轴 ti[]ti[]ti[] 中。

有序化,将时间轴割裂成若干段不相交且并集为全集的的小区间,一段时间一段时间地考虑。

像这种贪心贪不动,dppdp\ pdp p 不动的题目,我们就可以往网络流上靠了 。

其实是感觉是个网络流那它多半就是网络流。

现在就当大家已经想(猜)到这是道网络流了。

这道题问题就在于如何建立一个和原问题等价的网络流。

满足:任一时刻,一只老鼠最多吃一块奶酪,一块奶酪最多被一只老鼠吃。

因为网络流是同时多路径流,所以我们很难在网络流上面直观理解一对一。


本版块是对建图的描述。

刚开始,很容易想到。s,ts,ts,t 源汇点,1∼n1\sim n1∼n 的奶酪,源点 sss 分别与这 nnn 块奶酪连边,容量为对应奶酪的大小 ppp。

然后后面就开始 尼玛 神起来了。

  • 首先要将老鼠按吃的 速度从大到小 排序,最后面插个速度 000,再 差分 一下,得到新的速度序列 {v}\{v\}{v}。

    e.g.:5429→95420→4122\text{e.g.}:5\ 4\ 2\ 9\rightarrow 9\ 5\ 4\ 2\ 0\rightarrow 4\ 1\ 2\ 2e.g.:5 4 2 9→9 5 4 2 0→4 1 2 2。

    后面建图部分的第 iii 个老鼠点若未明确指出原老鼠 / 差分老鼠,则均指已经差分后的第 iii 个老鼠点。

差分过后,按划分的每个时间段重复以下的操作:

假设这个时间段 jjj 的长度为 time=ti[j+1]−ti[j]time=ti[j+1]-ti[j]time=ti[j+1]−ti[j]。

  • 枚举 1∼m1\sim m1∼m 老鼠,给其一个新编号 tot++tot++tot++,与汇点连边。

    第 iii 个老鼠连边容量为 vi⋅i⋅timev_i·i·\text{time}vi​⋅i⋅time。

    你肯定会疑惑这个容量太奇怪了。但先别着急。

    看图:

    vi⋅i:v_i·i:vi​⋅i: 差分值乘上它的差分数组内的编号。

    我们观察得到,假设差分数组为 ddd,原数组为 ooo,则有 ∑di⋅i=∑oi\sum d_i·i=\sum o_i∑di​⋅i=∑oi​。

    那么乘上 timetimetime 就是这个老鼠点在这个时间段能吃的奶酪限制。

    这个差分相当于将原老鼠切成了若干块,按相同块分类合并。

    这个在差分数组内的编号 iii 意思就是有 iii 只原老鼠能划分出这个 v[i]v[i]v[i] 块,统称一只差分老鼠。

  • 枚举 1∼n1\sim n1∼n 奶酪,对完全在这个时间段出现的奶酪继续操作:

    与每个老鼠连边,容量 vi⋅timev_i·timevi​⋅time。

    表示一只老鼠最多在一块奶酪上付出的努力。

    看图:

你可以将不同颜色的蓝线当作坐标轴的 x,yx,yx,y 基准轴,然后划分出每个速度老鼠小方格,一个小方格一个小方格地分配。

从上往下从左往右第 (x,y)(x,y)(x,y) 的方格可以理解为该时间段会有第 yyy 只原老鼠吃掉第 xxx 个奶酪的 vy⋅timev_y·timevy​⋅time 大小的部分。

每个奶酪会分配到某些行中的一个小方格,然后拼凑出来,相当于是吃掉了这个奶酪的一部分。


本板块是证明此种 奇怪神奇但是对的 网络流建图方式不会出现不合法的情况,即不存在某一时刻一只老鼠同时吃多个奶酪 / 一个奶酪同时被多只老鼠吃。

PS:本版块若未强调差分老鼠,则均指是原老鼠。

  • 先证明不存在一只老鼠同时吃多个奶酪的情况。

    假设排序后第 kkk 只老鼠在该时间段吃了 xxx 块奶酪,第 iii 块奶酪吃了时间 tit_iti​。

    如果 (∑ti)>time(\sum t_i)> time(∑ti​)>time,则表示存在一只老鼠同时吃多个奶酪(不合法)。

    首先第 kkk 个差分老鼠至少产生的流量都是 (∑ti)⋅vk(\sum t_i)·v_k(∑ti​)⋅vk​,而容量为 vk⋅k⋅timev_k·k·timevk​⋅k⋅time。

    此时有两种情况:

    • 有速度更快的老鼠能够帮吃超额部分(引起老鼠必须同时吃奶酪的部分),那么就可以分担。

      就不会存在 (∑ti)>time(\sum t_i)>time(∑ti​)>time。(也就是说看似不合法的流法可以通过调整变成合法流法)

    • 不能帮吃完所有超额部分。那么这些更快的老鼠肯定是吃过了,也就是它们在这个时间段每时每刻都在吃。

      在差分上会体现成前 k−1k-1k−1 个差分老鼠对 kkk 差分老鼠造成流量负担,加上原本流量,(∑ti)⋅vk+(k−1)⋅vk⋅time=k⋅vk⋅time+vk⋅((∑ti′)−time)>k⋅vk⋅time(\sum t_i)·v_k+(k-1)·v_k·time=k·v_k·time+v_k·\big((\sum t_i')-time\big)>k·v_k·time(∑ti​)⋅vk​+(k−1)⋅vk​⋅time=k⋅vk​⋅time+vk​⋅((∑ti′​)−time)>k⋅vk​⋅time,即流量大于容量,显然不可能,所以在网络流图上不可能跑成这样。(如果调整不了那么一开始就不可能跑成这种情况)

  • 再证明不存在一个 iii 奶酪同时被多只老鼠吃的情况。

    假设有 xxx 只老鼠吃了该奶酪,吃了时间 tit_iti​。

    如果 (∑ti)>tim(\sum t_i)>tim(∑ti​)>tim 则表示存在一个奶酪同时被多只老鼠吃。

    由于排名靠前的老鼠会对排名靠后的老鼠造成影响。即吃了同一个奶酪的 排名最后面的 老鼠流量为 (∑ti)⋅vk>ti⋅vk(\sum t_i)·v_k>t_i·v_k(∑ti​)⋅vk​>ti​⋅vk​(奶酪向每个差分老鼠的连边容量)。

    也不存在跑出这种情况的可能。


在建图板块,是从差分到原来;而在证明板块,是从原来到差分。可多思考一下。

因为这个建图是差分后的建图,所以如果要输出方案(即还原每只老鼠吃的时间)很有可能遇到差分还原后某只老鼠的时间是负数。
还原方法就是第一只差分老鼠的流量 /v/v/v 就是时间,然后把编号比它大的所有差分老鼠减去这个老鼠造成的流量贡献,以此类推。
网络流的流法很多种,我们只是知道最后流满没有。所以有可能某种流法看上去是不对的,但是它一定可以被调整成一种合法流法(优先满足编号小的差分老鼠)。
所以考察输出方案的话就显得不可做了。

code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 100000
#define maxm 500000
#define eps 1e-6
#define inf 1e9int s, t, cnt, T, n, m;
int head[maxn], cur[maxn], dep[maxn];
struct edge { int to, nxt; double flow; }E[maxm];
namespace NetworkFlow {queue < int > q;void init() { s = 0, t = n * m * 2 + 1, cnt = -1, memset( head, -1, sizeof( head ) ); }void addedge( int u, int v, double w ) {E[++ cnt] = { v, head[u], w }, head[u] = cnt;E[++ cnt] = { u, head[v], 0 }, head[v] = cnt;}bool bfs() {memset( dep, 0, sizeof( dep ) );memcpy( cur, head, sizeof( head ) );dep[s] = 1; q.push( s );while( ! q.empty() ) {int u = q.front(); q.pop();for( int i = head[u];~ i;i = E[i].nxt ) {int v = E[i].to;if( ! dep[v] and E[i].flow > eps ) {dep[v] = dep[u] + 1;q.push( v );}}}return dep[t];}double dfs( int u, double cap ) {if( u == t or cap < eps ) return cap;double flow = 0;for( int i = cur[u];~ i;i = E[i].nxt ) {int v = E[i].to; cur[u] = i;if( dep[v] == dep[u] + 1 ) {double w = dfs( v, min( cap, E[i].flow ) );if( w < eps ) continue;E[i ^ 1].flow += w;E[i].flow -= w;flow += w;cap -= w;if( cap < eps ) break;}}return flow;}double dinic() {double ans = 0;while( bfs() ) ans += dfs( s, inf );return ans;}
}struct node { double p, l, r; }c[maxn];
double v[maxn], ti[maxn];
double sum;
bool check( double delta ) {NetworkFlow :: init();for( int i = 1;i <= n;i ++ ) {NetworkFlow :: addedge( s, i, c[i].p );ti[i] = c[i].l, ti[i + n] = c[i].r + delta;}sort( ti + 1, ti + (n << 1 | 1) );int tot = n;for( int i = 1;i <= m;i ++ )for( int j = 1;j < (n << 1);j ++ ) {if( ti[j + 1] - ti[j] < eps ) continue;tot ++, NetworkFlow :: addedge( tot, t, ( ti[j + 1] - ti[j] ) * v[i] * i );for( int k = 1;k <= n;k ++ )if( c[k].l <= ti[j] and  ti[j + 1] <= delta + c[k].r )NetworkFlow :: addedge( k, tot, ( ti[j + 1] - ti[j] ) * v[i] );}return sum - NetworkFlow :: dinic() < eps;
}signed main() { scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%lf %lf %lf", &c[i].p, &c[i].l, &c[i].r );sum = 0; for( int i = 1;i <= n;i ++ ) sum += c[i].p;for( int i = 1;i <= m;i ++ ) scanf( "%lf", &v[i] );sort( v + 1, v + m + 1, []( int x, int y ) { return x > y; } ); for( int i = 1;i < m;i ++ ) v[i] = v[i] - v[i + 1];double l = 0, r = 5e7, ans;while( l + eps < r ) {double mid = ( l + r ) / 2;if( check( mid ) ) ans = mid, r = mid;else l = mid;}printf( "%.4f\n", ans );}return 0;
}

[ZJOI2010] 贪吃的老鼠(二分+差分+神仙建图网络流)相关推荐

  1. 差分约束问题 ---- 2019ccpc哈尔滨A. Artful Paintings[二分+差分约束+建图剪枝]

    题目链接 题目大意: 有N≤3e3N≤3e3N≤3e3个格子,你可以任意给每个格子染色,但是要满足M≤3e3M≤3e3M≤3e3限制条件,限制条件有两种类型: 区间[l,r][l,r][l,r]中被染 ...

  2. Luogu P2570 [ZJOI2010]贪吃的老鼠

    Luogu P2570 [ZJOI2010]贪吃的老鼠 题目描述 奶酪店里最近出现了\(m\)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产\(n\)块奶酪,其中第\(i\)块的 ...

  3. [ZJOI2010]贪吃的老鼠

    P2570 [ZJOI2010]贪吃的老鼠 在Ta的博客查看 显然二分,最大流判定 要满足两个条件: (1) 在任一时刻,一只老鼠最多可以吃一块奶酪: (2) 在任一时刻,一块奶酪最多被一只老鼠吃. ...

  4. 洛谷 P2570 [ZJOI2010]贪吃的老鼠

    洛谷 P2570 [ZJOI2010]贪吃的老鼠 题目 题目描述 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块奶酪,其中第i块的大小为pi,会在第ri秒 ...

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

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

  6. P2570 [ZJOI2010]贪吃的老鼠

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

  7. 【网络流】LGP2570 [ZJOI2010]贪吃的老鼠

    [题目] 原题地址 原题说的很清楚了,在这里也贴出来吧. 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块奶酪,其中第i块的大小为pi,会在第ri秒被生产出 ...

  8. 2016 计蒜之道 复赛 菜鸟物流的运输网络【拆点+思维建图+网络流】

    菜鸟物流的运输网络 菜鸟物流有自己的运输网络,网络中包含 nn 个城市物流集散中心,和 mm 对城市之间的运输线路(线路是双向的).菜鸟物流允许淘宝卖家自行确定包裹的运输路径,但只有一条限制规则:不允 ...

  9. HDU 4685 Prince and Princess(二分匹配加点建图+强连通分量)

    题目链接 Problem Description There are n princes and m princesses. Princess can marry any prince. But pr ...

最新文章

  1. leetcode-300 最长上升子序列
  2. aspen串联反应怎么输入_【精】反应器(反应釜)的结构和工作原理
  3. 【HM】第5课:JDBC连接MySQL数据库
  4. crank storyboard学习笔记(一)环境安装
  5. 乐安全 支持x86_国产EDA又进一步!芯华章发布全新仿真技术:x86、ARM等架构通吃...
  6. spring el 表达式的上下文关联到 ApplicationContext
  7. 操作数据库(对战小游戏)
  8. 计算机硬件系统都是看得见的,计算机组成硬件系统).doc
  9. 【云速建站】后台配置邮费
  10. 深入探索 IBM 数据分析和预测软件 - PASW Modeler
  11. 统计1到2021中6的个数
  12. SIFT算法 特征匹配
  13. Android小插件 —— 天气插件
  14. 软件创新实验室:微信小程序开发——音频录制与播放
  15. 草根IT江湖路之三:希望,在坚持之中
  16. 渐行渐远的是熟悉的身影
  17. CSO是什么?这家年增长48%的企业级软件公司告诉你
  18. python 将单词分割成字母_Python基于分隔符单词拆分列表
  19. 中国“钱”途光明10所大学
  20. ES6 计算属性名快速上手

热门文章

  1. 李国庆离开当当,广东消委会告长隆,智能校服提供定位功能,全球首个5G火车站来了,这就是今天的大新闻...
  2. 掌握神经网络模型的快捷方式
  3. path manipulation怎么解决_干货!终于!解决macOS下pyenv安装python3.8.2缺少tkinter模块的问题!...
  4. dw自动滚动图片_3分钟搞定图片懒加载
  5. 计算机专业杀毒,计算机病毒查杀
  6. 父与子一起学python3,父与子的编程之旅 与小卡特一起学Python 第3版(全彩印刷)...
  7. python 服务端框架_GitHub - edisonlz/fastor: Python服务端开发框架-极易上手,超出你的想象!...
  8. python服务器qt客户端_python3+PyQt5 创建多线程网络应用-TCP客户端和TCP服务器实例...
  9. mysql报4934_mysql-Mariadb语法错误1064(42000)
  10. 7-1 输出全排列 (20 分)(全排列+递归+图解)Come Baby