列表

详情


NC16924. [NOI2004]降雨量

描述

M国是个多雨的国家,尤其是P城,频繁的降雨给人们的出行带来了不少麻烦。为了方便行人雨天过马路,有关部门在每处人行横道的上空都安装了一种名为“自动伞”的装置。(如图1所示)

每把自动伞都可以近似地看作一块长方形的板,厚度不计。这种伞有相当出色的吸水能力,落到上面的雨水都会完全被伞顶的小孔吸入,并通过管道运走。不下雨时,这些伞闲置着。一旦下雨,它们便立刻开始作匀速率直线往返运动:从马路的一边以固定的速率移动到另一边,再从另一边以相同的速率返回,如此往复,直到雨停为止。任何时刻自动伞都不会越过马路的边界。有了自动伞,下雨天没带伞的行人只要躲在伞下行走,就不会被雨淋着了。

由于自动伞的大小有限,当需要使用自动伞过马路的人比较多时,一把自动伞显然是不够的,所以有关部门在几处主要的人行横道上空安装了多把自动伞。每把自动伞的宽度都等于人行横道的宽度,高度各不相同,长度不一定相同,移动速率也不一定相同。

现在已知一处人行横道的详细情况,请你计算从开始下雨到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;
}

上一题