Luogu2570  [ZJOI2010]贪吃的老鼠

题面描述

https://www.luogu.org/problemnew/show/P2570

然后题意大概就是m只老鼠,然后吃n个奶酪,已知

  • 每个奶酪体积为$p_i$
  • 每个奶酪原始保质期为$s_i到t_i$(在一个时间轴上的位置)
  • 每只老鼠吃奶酪的速度为$v_i$

要求

  • 同一时刻老鼠不能被原谅(不能吃两块奶酪)
  • 同一时刻奶酪不能原谅(不能被两只老鼠吃)

老鼠吃奶酪的时间可以为小数,且一个老鼠“一生”可以吃多块奶酪,一块奶酪“一生”可以多次被吃

现在你可以为奶酪$+T\ s$,也就是对于所有奶酪$t_i += T$

现在让你最小化$T$

题解

<!--瞎BB开始-->

好像机房就我没写了......

反正是要看题解的,这辈子逃不开题解的......

但题解看不懂连生活都维持不了这样子......
<!--瞎BB结束-->

还是DL不能依靠,还是自己看比较好

二分答案+最大流

建图方式:

首先对所有时间点离散化,记两个时间点之间的时间段长度为$tim$,然后把老鼠从大到小排序最后加个数字0,差分得到m个差分值,记为d,依次编号为$1,2,3...$

对奶酪建点,对时间点间的时间段拆点,拆成m个老鼠差分值

源点连向奶酪,容量 p

奶酪连向奶酪保质期内的时间段的老鼠差分点,容量为 老鼠差分值*时间段长度

老鼠差分点连向终点,容量为 老鼠差分值*时间段长度*老鼠差分点编号(排序后从大到小)

然后跑最大流,奶酪满流即为合法

下面配合一个实例来讲解证明为什么这样是对的(反正我是想不到的)

为了区分老鼠速度和差分后的速度,我们将拆出来的点称为“老鼠差分点“或”老鼠点“或指代意义的”点“

举个例子

老鼠分别有速度7,4,2

差分得到3,2,2

然后我们假设时间段长度为2

然后老鼠到t的流量限制为6,8,12

然后和奶酪的流量限制为6,4,4​

当且仅当这张图所有奶酪到起点的边满流的时候有解,其中如果一个老鼠$x$在一个时间段内吃了奶酪$y$,那么从该时间段$m-x$到$m$的老鼠差分点到奶酪$y$都会有流量$t*d_i$。这张图的工作原理是比较简单的(如果看不懂可以参考一下其它DL的博客)

最主要难以证明的是题目需要满足的两个要求。

  首先证明这张图满足一个老鼠同一时间只吃一个奶酪

  如果一个从大到小排名第$k$的老鼠吃了同一时间段的$x$块奶酪(如果不在同一时间段的话就不会有非法状态,如果有重叠则重叠部分和这个问题等价),设第$i$块奶酪吃了时间$t_i$,那么我们假设一个非法状态,也就是$(\Sigma{t_i}) > tim$,也就是一个老鼠同时吃多块奶酪,所以这个时候k号老鼠差分点产生的流量至少为$\Sigma{(t_i)}*d_k$,我们记为流量,但是我们对该老鼠的限制有$k*tim*d_k$,我们记为容量,我们要证明非法状态的$流量 > 容量$,在网络流中不存在。

这个时候我们有两种情况:

  1. 速度更快的老鼠还可以吃且可以吃超额部分(超额部分就是引起一只老鼠需要在同一时间吃两个奶酪的部分),那么就可以分担这个老鼠的任务,所以不存在这样的非法状态
  2. 速度更快的老鼠吃不完超额部分,那么这些老鼠一定是已经吃过了,所以根据差分上面$k-1$个老鼠差分点对这个老鼠差分点产生了流量负担,这个负担加上原有的流量为$\Sigma{(t_i)}*d_k+(k-1)*d_k*tim=k*tim*t_k+(\Sigma{(t_i)}-tim)$,由于$(\Sigma{(t_i)}-tim)>0$,所以$\Sigma{(t_i)}*d_k+(k-1)*d_k*tim>k*d_k*tim$,所以$流量 > 容量$,在网络流中无法实现

  然后证明这张图满足一个奶酪同时只被一只老鼠吃

  这个比较简单,一样假设一共有x只老鼠吃了奶酪,每一个吃了时间$t_i$,然后假设非法状态$(\Sigma{t_i}) > tim$,然后由于排名靠前的老鼠吃了的话那么在差分点中对排名较后的老鼠也会有时间上的影响,也就是吃了同一个奶酪的排名最后的老鼠流量为$\Sigma{(t_i)}*d_k$,大于边的容量$ti*d_k$,所以状态不存在。

代码如下:

 #include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream> //User's Lib #include <cmath>
#include <algorithm> using namespace std; #define DEBUG_PORT
#define DEBUG #ifdef ONLINE_JUDGE
#undef DEBUG_PORT
#undef DEBUG
#endif #ifdef DEBUG_PORT
#if __cplusplus >= 201103L
#ifdef DEBUG
template<typename T>
extern inline void Debug(T tar){
cerr << tar << endl;
}
template<typename Head, typename T, typename... Tail>
extern inline void Debug(Head head, T mid, Tail... tail){
cerr << head << ' ';
Debug(mid, tail...);
}
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
template<typename Head, typename T, typename... Tail>
extern inline void Debug(Head head, T mid, Tail... tail){
return ;
}
# pragma GCC diagnostic pop
# pragma message "Warning : pragma used"
#endif
#else
# pragma message "Warning : C++11 Not Use"
#ifdef DEBUG
template <typename T>
extern inline void Debug(T tar){
cerr << tar << endl;
}
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
template <typename T>
extern inline void Debug(T tar){
return ;
}
# pragma GCC diagnostic pop
# pragma message "Warning : pragma used"
#endif
#endif
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
template<typename Head, typename T, typename... Tail>
extern inline void Debug(Head head, T mid, Tail... tail){
return ;
}
template <typename T>
extern inline void Debug(T tar){
return ;
}
# pragma GCC diagnostic pop
# pragma message "Warning : pragma used"
#endif char buf[], *pc = buf; extern inline void Main_Init(){
static bool INITED = false;
if(INITED) fclose(stdin), fclose(stdout);
else {
fread(buf, , , stdin);
INITED = true;
}
} static inline int read(){
int num = ;
char c, sf = ;
while(isspace(c = *pc++));
if(c == ) sf = -, c = *pc ++;
while(num = num * + c - , isdigit(c = *pc++));
return num * sf;
} namespace LKF{
template <typename T>
extern inline T abs(T tar){
return tar < ? -tar : tar;
}
template <typename T>
extern inline void swap(T &a, T &b){
T t = a;
a = b;
b = t;
}
template <typename T>
extern inline void upmax(T &x, const T &y){
if(x < y) x = y;
}
template <typename T>
extern inline void upmin(T &x, const T &y){
if(x > y) x = y;
}
template <typename T>
extern inline T max(T a, T b){
return a > b ? a : b;
}
template <typename T>
extern inline T min(T a, T b){
return a < b ? a : b;
}
} //Source Code const int MAXK = ;
const int MAXN = ;
const int MAXM = ;
const double INF = 1e16;
const double eps = 1e-; inline bool comp(const double &a, const double &b){
double tmp = a - b;//int???
if(fabs(tmp) < eps) return ;
return a > b ? : -;
} int s = MAXN - , t = s + ; struct Queue{
int s, t;
int q[MAXN];
Queue(){s = , t = ;}
inline void clear(){
s = , t = ;
}
inline bool empty(){
return s > t;
}
inline int size(){
return t - s + ;
}
inline void push(int tar){
q[++ t] = tar;
}
inline int front(){
return q[s];
}
inline void pop(){
s ++;
}
}; struct Graph{
int tot;
int beginx[MAXN], endx[MAXM], nxt[MAXM];
double res[MAXM];
Graph(){
tot = ;
}
inline void Init(){
tot = ;
memset(beginx, , sizeof(beginx));
}
inline void add_edge(int u, int v, double r){
// Debug(u, "->", v, "[label = \"", r, "\"]");//Debug...
nxt[++ tot] = beginx[u], beginx[u] = tot, endx[tot] = v, res[tot] = r;
nxt[++ tot] = beginx[v], beginx[v] = tot, endx[tot] = u, res[tot] = ;
}
}; struct ISap{
Graph g;
Queue mession;
double max_f;
int cur[MAXN], d[MAXN], num[MAXN], pre[MAXN];
inline void bfs(){
mession.clear();
mession.push(t);
memset(d, , sizeof(d));
memset(num, , sizeof(num));
d[t] = ;
int u, v;
while(!mession.empty()){
u = mession.front();
mession.pop();
num[d[u]] ++;
for(int i = g.beginx[u]; i; i = g.nxt[i]){
v = g.endx[i];
if(!d[v] && comp(g.res[i ^ ], )){
d[v] = d[u] + ;
mession.push(v);
}
}
}
}
inline double dfs(int u, double now_f){
if(u == t) return now_f;
double ret_f = ;
for(int &i = cur[u]; i; i = g.nxt[i]){
int v = g.endx[i];
if(comp(g.res[i], ) && d[u] == d[v] + ){
double ret = dfs(v, min(g.res[i], now_f));
ret_f += ret, now_f -= ret;
g.res[i] -= ret, g.res[i ^ ] += ret;
if(d[s] >= MAXN - || !comp(now_f, )) return ret_f;
}
}
if(-- num[d[u]] == ) d[s] = MAXN - ;
++ num[++ d[u]];
cur[u] = g.beginx[u];
return ret_f;
}
inline double ISAP(){
bfs();
max_f = ;
memcpy(cur, g.beginx, sizeof(cur));
while(d[s] < MAXN - )
max_f += dfs(s, INF);
return max_f;
}
}isap; int n, m, sum;
int p[MAXK], r[MAXK], d[MAXK], ss[MAXK];
double tmp_arr[MAXK << ];
int cnt; inline bool check(double tar){
cnt = ;
isap.g.Init();
for(int i = ; i <= n; i++)
tmp_arr[++ cnt] = r[i], tmp_arr[++ cnt] = d[i] + tar;
sort(tmp_arr + , tmp_arr + + cnt);
cnt = unique(tmp_arr + , tmp_arr + + cnt) - tmp_arr - ;
for(int i = ; i <= n; i++)
isap.g.add_edge(s, i, p[i]);
for(int i = ; i <= cnt; i++){
double lst = tmp_arr[i - ], tim = tmp_arr[i] - lst;
for(int j = ; j <= m; j++)
isap.g.add_edge(n + (i - ) * m + j, t, j * tim * ss[j]);
for(int j = ; j <= n; j++)
if(r[j] <= lst && d[j] + tar >= tmp_arr[i])
for(int k = ; k <= m; k++)
isap.g.add_edge(j, n + (i - ) * m + k, tim * ss[k]);
}
return !comp(isap.ISAP(), sum);
} int main(){
Main_Init();
int T = read();
while(T --){
n = read(), m = read();
sum = ;
for(int i = ; i <= n; i++)
sum += (p[i] = read()), r[i] = read(), d[i] = read();
for(int i = ; i <= m; i++)
ss[i] = read();
ss[m + ] = ;
int tmp = ss[];
sort(ss + , ss + + m, greater<int>());
for(int i = ; i <= m; i++)
ss[i] -= ss[i + ];
double l = , r = 1.0 * sum / tmp, mid;
while(fabs(r - l) > eps){
mid = (l + r) / 2.0;
if(check(mid)) r = mid;
else l = mid;
}
printf("%.5lf\n", mid);
}
Main_Init();
return ;
}

Luogu2570 [ZJOI2010]贪吃的老鼠 ---- 网络流的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. [ZJOI2010]贪吃的老鼠

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

  7. P2570 [ZJOI2010]贪吃的老鼠

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

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

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

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

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

随机推荐

  1. octomap 安装使用

    由于工程实践中需要对机器人地图进行概率化估计并表示,故引入OctoMap库. 本文将介绍如何在Ubuntu环境下安装OctoMap. 如果你安装了ROS,那么一下的安装过程很可能会出错. 首先应该检查 ...

  2. __ATTR引发的编译错误【原创】

    有一天我编译内核模块驱动的时候发现如下错误 Linux kernel版本:4.1.15 error: negative width in bit-field '<anonymous>' 代 ...

  3. vue的学习(常用功能)

    1.介绍vue MVP和MVVM模式!!! mvp模式,其中m是模型是ajax请求数据, v是视图层(html),p是控制器,就是使用jq来实现业务逻辑相关操作(DOM操作很多) MVVM模式,其中M ...

  4. root权限使用vim不能修改权限

    1.背景: 有时候我们会发现使用root权限不能修改某个文件,大部分原因是曾经使用chattr将文件锁定了 2.chattr命令介绍: 用来改变文件属性,能防止root用户误删文件等作用 3.使用方法 ...

  5. 002_mtr_a network diagnostic tool

    一. mtr combines the functionality of the traceroute and ping programs in a single network diagnostic ...

  6. freeradius 错误: error:140890C7:SSL routines:ssl3_get_client_certificate:peer did not return a certificate

    在进行802.1x 测试时遇到如下问题: Waking up in 4.6 seconds.(156) Received Access-Request Id 82 from 192.168.1.126 ...

  7. zabbix系列(五)zabbix3.0.4 探索主机Discovery自动发现主机详细图文教程

    Zabbix 自动发现(Discovery)功能使用 随着监控主机不断增多,有的时候需要添加一批机器,特别是刚用zabbix的运维人员需要将公司的所有服务器添加到zabbix,如果使用传统办法去单个添 ...

  8. cacti系列(三)之cacti添加对mysql服务器主从的监控

    1.配置主从同步 主服务器: 建立从服务器的复制权限账号 GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repluser'@'192.16 ...

  9. androidpn 推送系统

    (文中部分内容来自网络,如无意中侵犯了版权,请告之!) XMPP协议: XMPP : The Extensible Messaging andPresence Protocol. 中文全称:可扩展通讯 ...

  10. S5PV210的根文件系统制作

    一.移植BusyBox1.下载BusyBox的源代码下载地址:http://www.busybox.net/downloads/,此处下载busybox-1.20.2.tar.bz2.2.解压并进入目 ...