Asia Hong Kong Regional Contest 2016
题目链接
B Kattis doors
题目分析与大意
就是在两个球之间找能够通过的最大半径,其实就是求几次点到线段的距离。(直接从代码中看)
关于直线和线段的距离公式参见链接。
代码
#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
题目大意及分析
这道题目就是对形如2a3b这样的数构成的序列进行操作的一个题目,主要就是要分析两个这样的数之间的最小公倍数和最大公因数的关系。
代码
#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 maxa1[N],mina1[N],maxb1[N],minb1[N];
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);
maxa1[1]=mina1[1]=da[1].a;
maxb1[1]=minb1[1]=da[1].b;
for(int i = 2;i <= n;i++)
{
maxa1[i] = max(maxa1[i-1],da[i].a);
mina1[i] = min(mina1[i-1],da[i].a);
maxb1[i] = max(maxb1[i-1],da[i].b);
minb1[i] = min(minb1[i-1],da[i].b);
}
if(n==1)
printf("%d %d %d %d\n",maxa1[n],maxb1[n],maxa1[n],maxb1[n]);
if(n==2)
{
printf("%d %d %d %d\n",maxa1[n],maxb1[n],maxa1[n],maxb1[n]);
printf("%d %d %d %d\n",mina1[n],minb1[n],mina1[n],minb1[n]);
}
if(n==3)
{
printf("%d %d %d %d\n",maxa1[n],maxb1[n],maxa1[n],maxb1[n]);
printf("%d %d %d %d\n",da[n].a,da[n].b,da[1].a,da[1].b);
printf("%d %d %d %d\n",mina1[n],minb1[n],mina1[n],minb1[n]);
}
if(n>=4)
{
printf("%d %d %d %d\n",maxa1[n],maxb1[n],maxa1[n],maxb1[n]);
printf("%d %d %d %d\n",maxa1[n],maxb1[n],da[1].a,da[1].b);
for(int i = 3;i < n-1;i++)
{
printf("%d %d %d %d\n",maxa1[n],maxb1[n],mina1[n],minb1[n]);
}
printf("%d %d %d %d\n",da[n].a,da[n].b,mina1[n],minb1[n]);
printf("%d %d %d %d\n",mina1[n],minb1[n],mina1[n],minb1[n]);
}
}
int main()
{
int t = 1;
// scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
J Taboo
题目大意及分析
给定n个由01构成的字符串,找到一个由01组成的字符串满足如下情况:1、保证其字串中没有这n个字符串中的任意一个;2、保证这个字符串的长度最长,如果有无限个这样的字符串,则输出-1;3、如果存在多个相同长度的该字符串,则输出字典序最小的那个。
我在做题的时候想到的是用字典树来做,后来才想到光用字典树肯定会漏掉情况,因为字典树考虑的只是前缀,但是按照题目中的意思,所谓的子串肯定不能只是包括前缀,中间的一部分子串也可能会包括上面的n个字符串,因此错误了。
考虑到要进行字符串的匹配,因此可能需要用到ac自动机,这里我之前也是没有怎么涉及过,这道题还需要再学习。
代码
后面补上