逗比三角形 sbtg

10 篇文章 0 订阅
2 篇文章 0 订阅
【题目描述】:
小 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值