【题目记录】——Asia Hong Kong Regional Contest 2016(16 HK)

本文详细探讨了两道数学问题,分别是关于平面几何中求圆心到障碍物最短距离的Bdoors问题,以及涉及数字运算和组合的CPlayingwithNumbers问题。通过模拟和数学分析,给出了求解思路和AC代码,涵盖了点到线段距离的计算、最大值和最小值的寻找等核心概念。
摘要由CSDN通过智能技术生成


题目集地址 16HK

16 HK补题单:B 平面几何 C 思维 J 字符串 K搜索

B doors

题目地址B doors
题目大意:如图Alex要进入通道找到Bob,问要想遇到Bob最Alex的最大半径是多少。
有两个长为l的门开着一定角度,宽为w的通道。
请添加图片描述
思路:模拟一下Alex路过的地方,找到在不同情况下圆心到周围障碍物的最短距离,即可。关键是要求出一个点到线段的距离。
关于直线和线段的距离公式参考计算几何之 点到直线的距离&点到线段的距离 代码模板与证明
AC代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;


double R,L,W,Alpha,Beta;

const double pi=acos(-1.0),eps=1e-9,inf=10000.0;

struct Point
{
    double x,y;
    Point()
    {
        x=y=0;
    }
    Point(double _x,double _y)
    {
        x=_x,y=_y;
    }
    Point operator+(Point v)
    {
        return Point(x+v.x,y+v.y);
    }
    Point operator-(Point v)
    {
        return Point(x-v.x,y-v.y);
    }
    double operator*(Point v)
    {
        return x*v.x+y*v.y;
    }
    bool operator==(Point v)
    {
        if(x==v.x&&y==v.y)
            return true;
        else
            return false;
    }
    double len()
    {
        return hypot(x,y);//计算直角三角形斜边长,其中两个参数为两个直角三角形的长度
    }
};

double cross(Point a,Point b)//求向量叉乘
{
    return a.x*b.y-a.y*b.x;
}
double dot(Point a,Point b)//求向量点积
{
    return a.x*b.x+a.y*b.y;
}

double distance_line(Point p,Point a,Point b)
{
	Point v1 = b - a,v2 = p - a;
	return fabs(cross(v1,v2) / v1.len());//cross是v1和v2的叉积
}
double dist_point_to_segment(Point p,Point a,Point b)//点p到线段ab的距离
{
	if(a == b)
		return (p-a).len();
	Point v1 = b - a,v2 = p - a,v3 = p - b;
	if(dot(v1,v2) < 0)	//dot是v1和v2的点积
		return v2.len();
	if(dot(v1,v3) > 0)
		return v3.len();
	return distance_line(p,a,b);
}

double cal(Point a,Point b,Point c,Point d)
{
    return min(min(dist_point_to_segment(a,c,d),
                   dist_point_to_segment(b,c,d)),
               min(dist_point_to_segment(c,a,b),
                   dist_point_to_segment(d,a,b)));
}

double solve()
{
    Point A(-inf,W),B(0,W);
    Point D(L,W),E(inf,W);
    Point G(L,0),H(inf,0);
    Alpha=pi-Alpha,Beta=pi-Beta;
    Point C=D+Point(cos(Alpha)*L,sin(Alpha)*L);
    Point F=G+Point(cos(Beta)*L,sin(Beta)*L);
    double ans=min(L,W);
    ans=min(ans,cal(A,B,C,D));
    ans=min(ans,cal(C,D,F,G));
    ans=min(ans,cal(D,E,F,G));
    ans/=2.0;
    ans=min(ans,R);
    ans=max(ans,0.0);
    return ans;
}

int main()
{
    int t;
    scanf("%lf%lf%lf",&R,&L,&W);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lf%lf",&Alpha,&Beta);
        printf("%.9f\n",solve());
    }
    return 0;
}

C Playing with Numbers 数学

题目地址C Playing with Numbers
题目大意:给n组数字a,b,表示数字 2 a 3 b 2^a3^b 2a3b,执行两种操作gcd(X,Y),lcm(X,Y),输出n-1行,每一行表示执行i-1次gcd操作,n-i次lcm操作,先输出最大值的a和b,然后输出最小值的a和b
思路:
首先两个数的gcd的结果用a和b表示就是min(a)和min(b),两个数的lcm是max(a)和max(b)
第1行是只执行lcm操作,最后的结果只有一个,max(a)和max(b)。
对称的最后一行是只执行gcd操作,最后也只有一个结果,就是min(a)和min(b)。
第2行是只执行一次gcd操作,先看最小值,我们可以将所有数字中最小的值留下来,其他的数字做lcm之后,得到的是其他数字的maxa和maxb,然后在和最小数字的a和b各取最小值即可(这里我们当时没有深究,直接输出了最小的值得a和b就过了)
对应的倒数第2行只执行一次lcm操作,我们最后取最大值即可。
中间的情况就比较简单了,最大值就是maxa和maxb,最小值就是mina和minb
然后n等于1,2,3的时候需要特殊判断一下就可以了
AC代码:

/*
**
*/
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N = 5e4+10;
struct num{
    int a,b;
}da[N];
int maxa,mina,maxb,minb;
bool com(num a,num b)
{
    return (a.a*log(2)+a.b*log(3)<b.a*log(2)+b.b*log(3));
}
void solve()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d%d",&(da[i].a),&(da[i].b));
    }
    sort(da+1,da+1+n,com);

    maxa=mina=da[1].a;
    maxb=minb=da[1].b;
    for(int i = 1;i <= n;i++)
    {
        maxa = max(maxa,da[i].a);
        mina = min(mina,da[i].a);
        maxb = max(maxb,da[i].b);
        minb = min(minb,da[i].b);
    }

    if(n==1)
    printf("%d %d %d %d\n",maxa,maxb,maxa,maxb);
    if(n==2)
    {
        printf("%d %d %d %d\n",maxa,maxb,maxa,maxb);
        printf("%d %d %d %d\n",mina,minb,mina,minb);
    }
    if(n==3)
    {
        printf("%d %d %d %d\n",maxa,maxb,maxa,maxb);
        printf("%d %d %d %d\n",da[n].a,da[n].b,da[1].a,da[1].b);
        printf("%d %d %d %d\n",mina,minb,mina,minb);
    }
    if(n>=4)
    {
        printf("%d %d %d %d\n",maxa,maxb,maxa,maxb);
        printf("%d %d %d %d\n",maxa,maxb,da[1].a,da[1].b);
        for(int i = 3;i < n-1;i++)
        {
            printf("%d %d %d %d\n",maxa,maxb,mina,minb);
        }
        printf("%d %d %d %d\n",da[n].a,da[n].b,mina,minb);
        printf("%d %d %d %d\n",mina,minb,mina,minb);
    }
}
int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int t = 1;
	while(t--)
	{
		solve();
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值