【题目描述】:
小 J 是一名 OI 退役滚粗文化课选手,他十分喜欢做题,尤其是裸题。他
现在有一个二维盒子和一些二维三角形,这个盒子拥有无限的高度和 L 的宽度。
而且他的三角形也都是一些锐角三角形或者是直角三角形。现在小 J 想把这些
三角形放入盒子里,由于小 J 从 txt 大神犇那里学会了魔法,所以小J 的三
角形既可以无视盒子边界又可以重叠放置,但是必须有一条边紧贴盒子底面所在
的直线。(垂直底边切除三角形的部分,放入底边宽度为L、高度无限的盒子中,
三角形底边贴着盒子的底边放置)
现在小J 想要最大化在盒子中的被三角形覆盖的区域的面积(即三角形间
的重叠部分只算一遍),请问这个最大值应该是多少?
【输入描述】:
一行一个整数T,代表数据组数。下面T 部分,每部分第一行两个整数N,L
分别代表三角形数量与盒子的宽度。下面N 行每行三个整数 ai,bi,ci 表示三
角形i 的三条边长。
【输出描述】:
T 行,每行一个实数代表盒子内部被三角形覆盖的区域的面积的最大值。
注:精确到小数点后4 位。
【样例输入】:
2
2 4
3 4 5
3 4 5
1 5
3 4 5
【样例输出】:
10.6667
6.0000
【时间限制、数据范围及描述】:
时间:1s 空间:256M
对于10%的数据有N <= 5
对于30%的数据有N <= 1000
对于60%的数据有 N <= 10^4
对于另外20%的数据有 L <= 1
小 J 是一名 OI 退役滚粗文化课选手,他十分喜欢做题,尤其是裸题。他
现在有一个二维盒子和一些二维三角形,这个盒子拥有无限的高度和 L 的宽度。
而且他的三角形也都是一些锐角三角形或者是直角三角形。现在小 J 想把这些
三角形放入盒子里,由于小 J 从 txt 大神犇那里学会了魔法,所以小J 的三
角形既可以无视盒子边界又可以重叠放置,但是必须有一条边紧贴盒子底面所在
的直线。(垂直底边切除三角形的部分,放入底边宽度为L、高度无限的盒子中,
三角形底边贴着盒子的底边放置)
现在小J 想要最大化在盒子中的被三角形覆盖的区域的面积(即三角形间
的重叠部分只算一遍),请问这个最大值应该是多少?
【输入描述】:
一行一个整数T,代表数据组数。下面T 部分,每部分第一行两个整数N,L
分别代表三角形数量与盒子的宽度。下面N 行每行三个整数 ai,bi,ci 表示三
角形i 的三条边长。
【输出描述】:
T 行,每行一个实数代表盒子内部被三角形覆盖的区域的面积的最大值。
注:精确到小数点后4 位。
【样例输入】:
2
2 4
3 4 5
3 4 5
1 5
3 4 5
【样例输出】:
10.6667
6.0000
【时间限制、数据范围及描述】:
时间:1s 空间:256M
对于10%的数据有N <= 5
对于30%的数据有N <= 1000
对于60%的数据有 N <= 10^4
对于另外20%的数据有 L <= 1
对于100%的数据有T<=5, N<=10^5, L<=10^6, 0<ai<=bi<=ci<=10^6, ai^2+bi^2>=ci^2
【题解Here!】
这题运用到了 微积分 的思想,混合了二分答案,巨坑啊。。。
将每个三角形分成 宽无穷小 的长条形,取前 L*宽度 个长条,算出覆盖面积即可。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define MAXN 100010
using namespace std;
int n,len;
struct node{
int a,b,c;
double s,h;
}angle[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
double getsum(int a,int b,int c){
double x=a,y=b,z=c,p=(x+y+z)*1.0000/2.00000;
double d=p*(p-a)*(p-b)*(p-c);
return sqrt(d);
}
bool check(double x){
double m=0;
for(int i=1;i<=n;i++)
if(angle[i].h>=x)
m+=(angle[i].h-x)*angle[i].a/angle[i].h;
return (m<=len);
}
void init(){
for(int i=1;i<=n;i++){
angle[i].a=read();angle[i].b=read();angle[i].c=read();
if(angle[i].a>angle[i].b)swap(angle[i].a,angle[i].b);
if(angle[i].b>angle[i].c)swap(angle[i].b,angle[i].c);
if(angle[i].a>angle[i].b)swap(angle[i].a,angle[i].b);
angle[i].s=getsum(angle[i].a,angle[i].b,angle[i].c);
angle[i].h=angle[i].s*2.0000/angle[i].a;
}
}
void work(){
double l=0,r=INT_MAX,mid,ans=0;
while(r-l>1e-7){
mid=(l+r)/2.00000;
if(check(mid))r=mid;
else l=mid;
}
for(int i=1;i<=n;i++)
if(angle[i].h>l)
ans+=(angle[i].h-l)*angle[i].a/angle[i].h*(angle[i].h-l)/2.0000;
ans+=l*len;
printf("%.4lf\n",ans);
}
int main(){
int t;
t=read();
while(t--){
n=read();len=read();
init();
work();
}
return 0;
}