[zjoi2010]cheese

题目:

贪吃的老鼠(cheese.c/cpp/pas/in/out)

时限:每个测试点10秒

[问题描述]

奶酪店里最近出现了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。你的答案和标准答案的绝对误差不应超过。

输入样例

2

2 2

13 0 4

10 1 3

4

2

1 1

1 0 2

1

输出样例

0.5

0

样例说明

第一组数据中:

l 第0到第1秒:第一只老鼠吃第一块奶酪;

l 第1到第3.5秒:

- 第一只老鼠吃第二块奶酪;

- 第二只老鼠吃第一块奶酪;

l 第3.5到第4.5秒:第一只老鼠吃第一块奶酪。

[数据范围]

思路:

  很好的一道题。。可惜我太弱了。。只想到要二分+网络流判定。。然后就什么也不会了。。只能看了题解。。

本题比较难的是一个时间点只能有一只老鼠,而一个老鼠一个时间点只能吃一个。。

朴素的建图是:

让S向每个奶酪连边,流量为pi

把老鼠按照时间段拆点,然后对于每个点, 向T连边,流量为该时间段能吃掉的奶酪数量

并且把奶酪向每个时间段的老鼠连边,流量为流量为该时间段能吃掉的奶酪数量

最后判断是否满流。。

但是,这样会出现有一个时间点有两只老鼠吃完的情况。。。怎么办?

题解就很巧了。。

我们对老鼠吃的速度也进行分段, 每段为对于前一只老鼠的速度差。。

试想一下,如果一个奶酪一个时间段(长度为T)内有若干只老鼠吃了,不妨设为为3只老鼠,a1,a2,a3,并且速度为s1,s2,s3, 同样假设s1< s2 < s3,

那么是不是这一段时间内老鼠吃了T1*s1 + T2(s2-s1) + T3*(s3-s2)

那是不是就可以把老鼠某个时间段吃的方案等价于多少个速度差吃的方案~~

so,构图如下:

让S向每个奶酪连边,流量为pi

对于每个速度段(第j段为sj)进行拆点为vij‘按照时间段(假设时间长为t)拆点,然后对于每个点, 向T连边,流量为该时间段该速度段sj在t时间内的产(sj*t*j)

并且把奶酪向每个时间段的速度段vij连边,流量为sj*t

最后判断是否满流。。

这样一来,每个速度段在每个时间段最多只有出现一个,这样就满足一对一的情况。。

好吧。。说的很混乱。。直接上代码吧。。

code:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <vector>
  8 #define maxn 1200
  9 #define Inf 0x3fffffff
 10 #define maxm 210000
 11 #define eps 1e-8
 12 #define M0(a) memset(a, 0, sizeof(a))
 13 using namespace std;
 14 int cmp(double x, double y){
 15     return fabs(x - y) <= eps;
 16 }
 17 int sgn(double x){
 18     return (x > eps) - (x < -eps);
 19 }
 20 struct oo{
 21       int y, next;
 22       double f;
 23 };
 24 struct MaxFlow{
 25        int n, S, T, tot;
 26        int son[maxn], dist[maxn], gap[maxn];
 27        oo e[maxm];
 28        double sap(int x, double aug){
 29            if (x == T) return aug;
 30            int mind = n;
 31            double sum = 0, f;
 32            for (int p = son[x]; p != -1; p = e[p].next){
 33                   int y = e[p].y;
 34                   if (dist[y] + 1 == dist[x] && e[p].f){
 35                        f = sap(y, min(e[p].f, aug - sum));
 36                        e[p].f -= f;
 37                        e[p^1].f += f;
 38                        sum += f;
 39                        if (sum == aug || dist[S] >= n) return sum;
 40                   }
 41                   if (e[p].f) mind = min(mind, dist[y]);
 42            }
 43            if (!sum){
 44                if (!(--gap[dist[x]])) dist[S] = n;
 45                ++gap[dist[x] = mind + 1];
 46            }
 47            return sum;
 48        }
 49
 50        void add(int x, int y, double f){
 51             e[tot].y = y; e[tot].f = f;
 52             e[tot].next = son[x]; son[x] = tot++;
 53             e[tot].y = x; e[tot].f = 0;
 54             e[tot].next = son[y]; son[y] = tot++;
 55        }
 56
 57        void init(int S, int T, int n){
 58             memset(son, -1, sizeof(son));
 59             tot = 0;
 60             this->S = S, this->T = T, this->n = n;
 61        }
 62        double maxflow(){
 63             M0(gap);
 64             M0(dist);
 65             gap[0] = n;
 66             double ans = 0;
 67             while (dist[S] < n) ans += sap(S, Inf);
 68             return ans;
 69        }
 70 } F;
 71 int n, m, p[maxn], r[maxn], d[maxn], s[maxn];
 72
 73 void init(){
 74      scanf("%d%d", &n, &m);
 75      for (int i = 1; i <= n; ++i)
 76         scanf("%d%d%d", &p[i], &r[i], &d[i]);
 77      for (int i = 1; i <= m; ++i)
 78         scanf("%d", &s[i]);
 79      sort(s+1, s+1+m, greater<int>());
 80      for (int i = 1; i < m; ++i)
 81          s[i] -= s[i+1];
 82 }
 83
 84 int check(double add){
 85     vector<double> v;
 86     for (int i = 1; i <= n; ++i)
 87          v.push_back(r[i]), v.push_back(d[i]+add);
 88     sort(v.begin(), v.end());
 89     v.erase(unique(v.begin(), v.end(), cmp), v.end());
 90     int S = 0,  T = m*(v.size()-1)+n+1;
 91     F.init(0, T, T+1);
 92     for (int i = 1; i <= n; ++i)
 93        F.add(S, i, p[i]);
 94     for (int i = 0; i + 1 < (int)v.size(); ++i){
 95          double dur = v[i+1]-v[i];
 96          for (int j = 1; j <= m; ++j)
 97              F.add(i * m + n + j, T, j*s[j]*dur);
 98          for (int j = 1; j <= n; ++j)
 99              if (sgn(r[j]-v[i]) <= 0 && sgn(d[j]+add-v[i+1]) >= 0)
100                 for (int k = 1; k <= m; ++k)
101                     F.add(j, n+i*m+k, dur*s[k]);
102     }
103     double sum = 0;
104     for (int i = 1; i <= n; ++i)
105        sum += p[i];
106     double flow = F.maxflow();
107     return sgn(flow - sum) == 0;
108 }
109
110 void solve(){
111      double l = 0, r = 3000000;
112      for (int i = 0; i < 40; ++i){
113          double mid = (l + r) / 2.0;
114          check(mid) ? r = mid : l = mid;
115      }
116      printf("%.7lf\n", l);
117 }
118
119 int main(){
120     freopen("a.in", "r", stdin);
121     freopen("a.out", "w", stdout);
122     int T;
123     scanf("%d", &T);
124     while (T--){
125           init();
126           solve();
127     }
128 }

 

[zjoi2010]cheese,布布扣,bubuko.com

时间: 2024-10-06 21:02:55

[zjoi2010]cheese的相关文章

Luogu P2570 [ZJOI2010]贪吃的老鼠

Luogu P2570 [ZJOI2010]贪吃的老鼠 题目描述 奶酪店里最近出现了\(m\)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产\(n\)块奶酪,其中第\(i\)块的大小为\(pi\),会在第\(ri\)秒被生产出来,并且必须在第\(di\)秒之前将它吃掉.第j只老鼠吃奶酪的速度为\(sj\),因此如果它单独吃完第i快奶酪所需的时间为\(pi/sj\).老鼠们吃奶酪的习惯很独特,具体来说: (1) 在任一时刻,一只老鼠最多可以吃一块奶酪: (2) 在任一时刻,一

bzoj1834: [ZJOI2010]network 网络扩容

努力看了很久样例一直过不了...然后各种输出中间过程啊巴拉巴拉弄了1h,没办法了...然后突然想到啊原来的边可以用啊为什么不用...于是A了...感人肺腑 #include<cstdio> #include<cstring> #include<queue> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n

1833: [ZJOI2010]count 数字计数

1833: [ZJOI2010]count 数字计数 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 2951  Solved: 1307[Submit][Status][Discuss] Description 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. Input 输入文件中仅包含一行两个整数a.b,含义如上所述. Output 输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次.

BZOJ_1833_[ZJOI2010]_数字计数_(数位dp)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1833 统计\(a~b\)中数字\(0,1,2,...,9\)分别出现了多少次. 分析 数位dp真是细节又多又容易出错,我都懒得看题解,所以也就懒得写题解了... 注意细节吧还是... 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 ll a,b; 6 ll A[10],B[10],n

[2016-03-28][HDU][1078][FatMouse and Cheese]

时间:2016-03-28 17:40:34 星期一 题目编号:[2016-03-28][HDU][1078][FatMouse and Cheese] #include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int maxn = 100 + 10; int a[maxn][maxn]; int dp[maxn][maxn]; int n ,k; int d

记忆化搜索,FatMouse and Cheese

1.从gird[0][0]出发,每次的方向搜索一下,每次步数搜索一下 for(i=0; i<4; i++) { for(j=1; j<=k; j++) { int tx=x+d[i][0]*j; int ty=y+d[i][1]*j; if(tx>=0&&tx<n&&ty>=0&&ty<n&&grid[x][y]<grid[tx][ty]) { int temp=memSearch(tx,ty); i

HDU1078 FatMouse and Cheese 【内存搜索】

FatMouse and Cheese Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4966    Accepted Submission(s): 2035 Problem Description FatMouse has stored some cheese in a city. The city can be considere

UVA1001 Say Cheese

如果没有洞,那么任意两点的最短距离就是直线距离,洞里是瞬间的,所以看成一个点就行了(其实点也可以当作半径为0的洞来处理),洞到洞的最短距离都是圆心距离减去半径.剩下的就是完全图求单源最短路径,用不加堆优化的dijkstra就行了O(n^2). #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 102; int x[maxn],y[maxn],z[maxn],r[maxn]; d

hdu 1078 FatMouse and Cheese

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5701    Accepted Submission(s): 2320 Problem Description FatMouse has stored some cheese in a city. The city can be considered as a square grid of