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. Java注解之Retention、Documented、Target、Inherited介绍

    先看代码,后面一个个来解析: @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.METHOD, ElementType. ...

  2. 【vim】查找重复的连续的单词

    当你很快地打字时,很有可能会连续输入同一个单词两次,就像 this this.这种错误可能骗过任何一个人,即使是你自己重新阅读一遍也不可避免.幸运的是,有一个简单的正则表达式可以用来预防这个错误.使用 ...

  3. UML和模式应用5:细化阶段(8)---逻辑架构和UML包图

    1.前言 本章是从面向分析的工作过度到软件设计 典型的OO系统设计的基础是若干架构层,如UI层.应用逻辑(领域)层 本章简要考察逻辑分层架构和相关UML表示法 2.逻辑架构和层 逻辑架构 逻辑架构是软 ...

  4. ARMV8 Procedure Call Standard

    1.前言 2.  术语说明 Term Note ABI Application Binary Interface 应用程序二进制接口 EABI Embedded ABI  嵌入式ABI PCS Pro ...

  5. Python3学习笔记08-tuple

    元组与列表类似,不同之处在于元组的元素不能修改 元组使用小括号,列表使用方括号 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可 tup1 = ('Google', 'Runoob', 19 ...

  6. @PathVariable和@RequestParam

    @PathVariable 当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariabl ...

  7. MFC CStdioFile

    读Text文件 void CNWiReworkDlg::ReadHexFile() { using namespace std; CStdioFile file; file.Open(hexFileP ...

  8. centos7和centos6.5环境rpm方式安装mysql5.7和mysql5.6详解

    centos环境安装mysql5.7 其实不建议安装mysql5.7 语法和配置可能和以前的版本区别较大,多坑,慎入 1.yum方式安装(不推荐) a.安装mysql5.7 yum源 centos6: ...

  9. TCP/IP、Http大纲

    TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据.关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:“我们在传输数据时,可以只 ...

  10. 【ES】学习3-请求体查询

    1.空查询 GET /index_2014*/type1,type2/_search {} GET /_search { , } 2.查询表达式 DSL只需将查询语句传递给 query 参数 GET ...