题目描述
降雨量 【问题描述】 M国是个多雨的国家,尤其是P城,频繁的降雨给人们的出行带来了不少麻烦。为了方便行人雨天过马路,有关部门在每处人行横道的上空都安装了一种名为“自动伞”的装置。(如图1所示) 图1 每把自动伞都可以近似地看作一块长方形的板,厚度不计。这种伞有相当出色的吸水能力,落到上面的雨水都会完全被伞顶的小孔吸入,并通过管道运走。不下雨时,这些伞闲置着。一旦下雨,它们便立刻开始作匀速率直线往返运动:从马路的一边以固定的速率移动到另一边,再从另一边以相同的速率返回,如此往复,直到雨停为止。任何时刻自动伞都不会越过马路的边界。有了自动伞,下雨天没带伞的行人只要躲在伞下行走,就不会被雨淋着了。 由于自动伞的大小有限,当需要使用自动伞过马路的人比较多时,一把自动伞显然是不够的,所以有关部门在几处主要的人行横道上空安装了多把自动伞。每把自动伞的宽度都等于人行横道的宽度,高度各不相同,长度不一定相同,移动速率也不一定相同。 现在已知一处人行横道的详细情况,请你计算从开始下雨到T秒钟后的这段时间内,一共有多少体积的雨水降落到人行横道上。 【输入文件】 第一行有四个整数N,W,T,V。N表示自动伞的数目,W表示马路的宽度,T表示需要统计从开始下雨到多长时间后的降雨情况,V表示单位面积单位时间内的降雨体积。 为了描述方便,我们画出了一个如图2所示的天空中五把伞的剖面图,取马路左边界为原点,取向右为x轴正方向,取向上为y轴正方向,建立平面直角坐标系。这样,每把自动伞都可以看作平面上的一条线段。 图2 接下来的N行,每行用三个整数描述一把自动伞。第一个数x是伞的初始位置,用它左端点的横坐标表示。第二个数l是伞的长度,即x方向上的尺寸。第三个数v是伞的速度,v的大小表示移动的速率。如果v>0,表示开始时伞向右移动;如果v<0,表示开始时伞向左移动;如果v=0,表示伞不动。 【输出文件】 输出文件只包含一个实数,表示从开始下雨到T秒钟后,一共有多少体积的水降落到人行横道上。输出结果精确到小数点后第二位。 【约定】 雨点均匀地匀速竖直下落 自动伞和马路两者都是水平的 自动伞的宽度和人行横道的宽度相等,都等于1 所有自动伞的往返次数之和不超过250,一来一回算一个往返。 【样例输入】 2 4 3 10 0 1 1 3 1 -1 【样例输出】 65.00
解法1:simpson自适应公式
1 /* 2 *Problem: NOI2004 降雨量 3 *Author : Chen Yang 4 *Time : 2012.6.11 4:00 pm 5 *State : 90分 6 *Memo : 计算几何之simpson 7 */ 8 #include <cstdio> 9 #include <cstdlib> 10 #include <cmath> 11 #include <cstring> 12 #include <string> 13 #include <algorithm> 14 using namespace std; 15 typedef double DB; 16 const int maxn=301, inf = 100000000; 17 const DB zero = 1e-8; 18 int n, m, w, T, V; 19 struct line {DB x,y,len,k,L,R;} L[5010]; 20 struct inter {DB l,r;} c[maxn]; 21 22 bool cmp(const inter &a, const inter &b) 23 {return a.l<b.l || (a.l == b.l && a.r < b.r);} 24 25 DB f(DB x) 26 { 27 DB s = 0; int p = 0; 28 for (int i=1; i<=m; ++i) 29 if (L[i].L<x && x<L[i].R) 30 { 31 if (fabs(L[i].k)>zero) 32 { 33 DB t1=(x-L[i].x)*L[i].k+L[i].y; 34 DB t2=(x-L[i].x-L[i].len)*L[i].k+L[i].y; 35 c[++p].l = max(L[i].y,min(t1,t2)); 36 c[p].r = min(L[i].y+fabs(L[i].k*(L[i].R-L[i].L-L[i].len)),max(t1,t2)); 37 } else return T; 38 } 39 if (!p) return 0; 40 sort(c+1, c+p+1, cmp); 41 DB l = c[1].l, r = c[1].r; 42 for (int i=2; i<=p; ++i) 43 if (c[i].l>r) s += r-l, l = c[i].l, r = c[i].r; 44 else r = max(c[i].r,r); 45 s += r-l; 46 return s; 47 } 48 49 inline DB simpson(DB a, DB b, DB fa, DB fm, DB fb) 50 { return (b-a)/6*(fa+4*fm+fb); } 51 52 DB calc(DB l, DB fl, DB m, DB fm, DB r, DB fr, DB pre) 53 { 54 DB ls=(l+m)/2, rs=(m+r)/2, fls=f(ls), frs=f(rs); 55 DB la=simpson(l,m,fl,fls,fm), ra=simpson(m,r,fm,frs,fr); 56 return fabs(la+ra-pre)<zero? pre:calc(l,fl,ls,fls,m,fm,la)+calc(m,fm,rs,frs,r,fr,ra); 57 } 58 59 inline DB area(DB l, DB r) 60 { 61 DB m=(l+r)/2, fl=f(l), fr=f(r), fm=f(m); 62 DB pre = simpson(l,r,fl,fm,fr); 63 return calc(l,fl,m,fm,r,fr,pre); 64 } 65 66 void check(DB x, DB y, DB len, DB v, DB t) 67 { 68 DB l = min(x,x+t*v), r = max(x+len,x+len+t*v); 69 L[++m].L = l, L[m].R = r, L[m].k = 1/v; 70 L[m].x = x, L[m].y = y, L[m].len = len; 71 if (r>w) 72 { 73 L[m].R = w; 74 check(w-len, y+(w-len-x)/v, len, -v, t-(w-len-x)/v); 75 } else 76 if (l<-zero) 77 { 78 L[m].L = 0; 79 check(0, y-x/v, len, -v, t+x/v); 80 } 81 } 82 83 int main() 84 { 85 freopen("rainfall.in", "r", stdin); 86 freopen("rainfall.out", "w", stdout); 87 scanf("%d%d%d%d", &n, &w, &T, &V); 88 for (int i=1; i<=n; ++i) 89 { 90 DB x, l, v; 91 scanf("%lf%lf%lf", &x, &l, &v); 92 if (fabs(v)>zero && (x!=0 || l!=w)) check(x,0,l,v,(DB) T); 93 else L[++m].k = 0, L[m].L = x, L[m].R = x+l; 94 } 95 printf("%.2lf\n", (T*w-area(0,w))*V); 96 return 0; 97 }
解法2:分段求面积
1 /* 2 *Problem: NOI2004 降雨量 3 *Author : Chen Yang 4 *Time : 2012.6.11 4:00 pm 5 *State : AC 6 *Memo : 计算几何之平行四边形面积并 7 */ 8 #include <cstdio> 9 #include <cstdlib> 10 #include <cmath> 11 #include <cstring> 12 #include <string> 13 #include <algorithm> 14 using namespace std; 15 typedef double DB; 16 const int maxn=301, maxm=5010, inf = 100000000; 17 const DB zero = 1e-8; 18 int n, m, w, T, V, fs; 19 DB a[maxm]; 20 struct line {DB x,y,len,k,L,R;} L[maxm]; 21 struct inter {DB l,r;} c[maxn]; 22 23 bool cmp(const inter &a, const inter &b) 24 {return a.l<b.l || (a.l == b.l && a.r < b.r);} 25 26 DB f(DB x) 27 { 28 DB s = 0; int p = 0; 29 for (int i=1; i<=m; ++i) 30 if (L[i].L<=x && x<=L[i].R) 31 { 32 c[++p].l = (x-L[i].x)*L[i].k+L[i].y; 33 c[p].r = c[p].l+L[i].len; 34 } 35 if (!p) return 0; 36 sort(c+1, c+p+1, cmp); 37 DB l = c[1].l, r = c[1].r; 38 for (int i=2; i<=p; ++i) 39 if (c[i].l>r) s += r-l, l = c[i].l, r = c[i].r; 40 else r = max(c[i].r,r); 41 s += r-l; 42 return s; 43 } 44 45 inline DB area() 46 { 47 DB s = 0; 48 for (int i=2; i<=fs; ++i) 49 s += (f(a[i])+f(a[i-1]))*(a[i]-a[i-1])/2; 50 return s; 51 } 52 53 void check(DB x, DB y, DB len, DB v, DB t) 54 { 55 L[++m].L = x, L[m].R = x+t, L[m].k = v; 56 L[m].x = x, L[m].y = y, L[m].len = len; 57 DB l = y+t*v, r = y+len+t*v; 58 if (r>w+zero) 59 { 60 L[m].R = x+(w-len-y)/v; 61 check(L[m].R, w-len, len, -v, t-(w-len-y)/v); 62 } else 63 if (l<-zero) 64 { 65 L[m].R = x-y/v; 66 check(L[m].R, 0, len, -v, t+y/v); 67 } else a[++fs] = x+t; 68 a[++fs] = x; 69 } 70 71 inline bool cross(int i, int j) 72 { 73 return L[i].R>=L[j].L && L[i].L<=L[j].R && fabs(L[i].k-L[j].k)>zero; 74 } 75 76 void get_p(int i, int j) 77 { 78 DB x1 = L[i].x, x2 = L[j].x, y1 = L[i].y, y2 = L[j].y; 79 DB k1 = L[i].k, k2 = L[j].k, L1 = L[i].L, L2 = L[j].L; 80 DB R1 = L[i].R, R2 = L[j].R, len1 = L[i].len, len2 = L[j].len; 81 DB x = (y2-y1+x1*k1-x2*k2)/(k1-k2); 82 if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; 83 x = (y2+len2-y1+x1*k1-x2*k2)/(k1-k2); 84 if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; 85 x = (y2-len1-y1+x1*k1-x2*k2)/(k1-k2); 86 if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; 87 x = (y2+len2-len1-y1+x1*k1-x2*k2)/(k1-k2); 88 if (L1<=x && x<=R1 && L2<=x && x<=R2) a[++fs] = x; 89 } 90 91 int main() 92 { 93 freopen("rainfall.in", "r", stdin); 94 freopen("rainfall.out", "w", stdout); 95 scanf("%d%d%d%d", &n, &w, &T, &V); 96 for (int i=1; i<=n; ++i) 97 { 98 DB x, l, v; 99 scanf("%lf%lf%lf", &x, &l, &v); 100 if (x || l!=w) check(0,x,l,v,(DB) T); 101 else {printf("0.00"); return 0;}; 102 } 103 for (int i=1; i<=m; ++i) 104 for (int j=1; j<=m; ++j) 105 if (i!=j && cross(i,j)) get_p(i,j); 106 sort(a+1, a+fs+1); 107 printf("%.2lf\n", (T*w-area())*V); 108 return 0; 109 }