NC16924. [NOI2004]降雨量
描述
每把自动伞都可以近似地看作一块长方形的板,厚度不计。这种伞有相当出色的吸水能力,落到上面的雨水都会完全被伞顶的小孔吸入,并通过管道运走。不下雨时,这些伞闲置着。一旦下雨,它们便立刻开始作匀速率直线往返运动:从马路的一边以固定的速率移动到另一边,再从另一边以相同的速率返回,如此往复,直到雨停为止。任何时刻自动伞都不会越过马路的边界。有了自动伞,下雨天没带伞的行人只要躲在伞下行走,就不会被雨淋着了。
由于自动伞的大小有限,当需要使用自动伞过马路的人比较多时,一把自动伞显然是不够的,所以有关部门在几处主要的人行横道上空安装了多把自动伞。每把自动伞的宽度都等于人行横道的宽度,高度各不相同,长度不一定相同,移动速率也不一定相同。
现在已知一处人行横道的详细情况,请你计算从开始下雨到T秒钟后的这段时间内,一共有多少体积的雨水降落到人行横道上。
输入描述
第一行有四个整数N,W,T,V。N表示自动伞的数目,W表示马路的宽度,T表示需要统计从开始下雨到多长时间后的降雨情况,V表示单位面积单位时间内的降雨体积。
为了描述方便,我们画出了一个如图2所示的天空中五把伞的剖面图,取马路左边界为原点,取向右为x轴正方向,取向上为y轴正方向,建立平面直角坐标系。这样,每把自动伞都可以看作平面上的一条线段。接下来的N行,每行用三个整数描述一把自动伞。第一个数x是伞的初始位置,用它左端点的横坐标表示。第二个数l是伞的长度,即x方向上的尺寸。第三个数v是伞的速度,v的大小表示移动的速率。如果v>0,表示开始时伞向右移动;如果v<0,表示开始时伞向左移动;如果v=0,表示伞不动。
输出描述
只包含一个实数,表示从开始下雨到T秒钟后,一共有多少体积的水降落到人行横道上。输出结果精确到小数点后第二位。
示例1
输入:
2 4 3 10 0 1 1 3 1 -1
输出:
65.00
C++11(clang++ 3.9) 解法, 执行用时: 8ms, 内存消耗: 480K, 提交时间: 2019-01-07 17:01:24
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> using namespace std; typedef double DB; const int maxn=301, maxm=5010, inf = 100000000; const DB zero = 1e-8; int n, m, w, T, V, fs; DB a[maxm]; struct line {DB x,y,len,k,L,R;} L[maxm]; struct inter {DB l,r;} c[maxn]; bool cmp(const inter &a, const inter &b) {return a.l<b.l || (a.l == b.l && a.r < b.r);} DB f(DB x) { DB s = 0; int p = 0; for (int i=1; i<=m; ++i) if (L[i].L<=x && x<=L[i].R) { c[++p].l = (x-L[i].x)*L[i].k+L[i].y; c[p].r = c[p].l+L[i].len; } if (!p) return 0; sort(c+1, c+p+1, cmp); DB l = c[1].l, r = c[1].r; for (int i=2; i<=p; ++i) if (c[i].l>r) s += r-l, l = c[i].l, r = c[i].r; else r = max(c[i].r,r); s += r-l; return s; } inline DB area() { DB s = 0; for (int i=2; i<=fs; ++i) s += (f(a[i])+f(a[i-1]))*(a[i]-a[i-1])/2; return s; } void check(DB x, DB y, DB len, DB v, DB t) { L[++m].L = x, L[m].R = x+t, L[m].k = v; L[m].x = x, L[m].y = y, L[m].len = len; DB l = y+t*v, r = y+len+t*v; if (r>w+zero) { L[m].R = x+(w-len-y)/v; check(L[m].R, w-len, len, -v, t-(w-len-y)/v); } else if (l<-zero) { L[m].R = x-y/v; check(L[m].R, 0, len, -v, t+y/v); } else a[++fs] = x+t; a[++fs] = x; } inline bool cross(int i, int j) { return L[i].R>=L[j].L && L[i].L<=L[j].R && fabs(L[i].k-L[j].k)>zero; } void get_p(int i, int j) { DB x1 = L[i].x, x2 = L[j].x, y1 = L[i].y, y2 = L[j].y; DB k1 = L[i].k, k2 = L[j].k, L1 = L[i].L, L2 = L[j].L; DB R1 = L[i].R, R2 = L[j].R, len1 = L[i].len, len2 = L[j].len; DB x = (y2-y1+x1*k1-x2*k2)/(k1-k2); if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; x = (y2+len2-y1+x1*k1-x2*k2)/(k1-k2); if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; x = (y2-len1-y1+x1*k1-x2*k2)/(k1-k2); if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; x = (y2+len2-len1-y1+x1*k1-x2*k2)/(k1-k2); if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; } int main() { scanf("%d%d%d%d", &n, &w, &T, &V); for (int i=1; i<=n; ++i) { DB x, l, v; scanf("%lf%lf%lf", &x, &l, &v); if (x || l!=w) check(0,x,l,v,(DB) T); else {printf("0.00"); return 0;}; } for (int i=1; i<=m; ++i) for (int j=1; j<=m; ++j) if (i!=j && cross(i,j)) get_p(i,j); sort(a+1, a+fs+1); printf("%.2lf\n", (T*w-area())*V); return 0; }