http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1008&cid=881
题意:
给出一个正三角形和一个质点的位置矢量及速度矢量,点严格在三角形内部。点如果撞到边界会像光路一样镜面反射,速度不变。统计第k次碰撞的时间,保证前k次不会撞到夹角。
解析:
等同于在这个图中移动
以水平的那种线为例。
直接二分运动的距离 l e n len len,求出终点在 y y y轴上的投影高度: h e i g h t height height。
h e i g h t / ( 3 2 L ) height/(\dfrac{\sqrt3}{2}L) height/(23L)就是对应的倍数 P P P。
- 如果 V y ≥ 0 Vy\geq0 Vy≥0,碰撞水平线的条数为 ⌊ P ⌋ \lfloor P\rfloor ⌊P⌋(向上碰撞 P ∈ ( 0 , i n f ] P\in(0,inf] P∈(0,inf])
- 否则为 1 − ⌈ P ⌉ 1-\lceil P\rceil 1−⌈P⌉(向下碰撞 P ∈ [ − inf , 1 ) P\in[-\inf,1) P∈[−inf,1))
再来考虑碰撞左边的线 ( y = 3 x + b ) (y=\sqrt3x+b) (y=3x+b)和右边的线 ( y = − 3 x + b ) (y=-\sqrt3x+b) (y=−3x+b)。
最简单的处理方法就是把坐标系换一下后套用上面的办法求。
换坐标系:
以左边的线(图3)为例,方向向量直接逆时针旋转120度即可,点的话 Y Y Y坐标为与左边的线的距离, X X X坐标为与法线的距离, X X X坐标需要用叉积判断一下正负。
代码:
/*
* Author : Jk_Chen
* Date : 2020-07-28-14.13.52
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define F double
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<"> "<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
F eps=1e-8;
const F pi=acos(-1);
struct point{
F x,y;
point(){}
point(F x,F y):x(x),y(y){}
};
typedef point Vector;
typedef point Point;
Vector operator + (Vector a, Vector b){//向量加法
return Vector(a.x + b.x, a.y + b.y);
}
Vector operator - (Vector a, Vector b){//向量减法
return Vector(a.x - b.x, a.y - b.y);
}
Vector operator * (Vector a, double p){//向量数乘
return Vector(a.x*p, a.y*p);
}
Vector operator / (Vector a, double p){//向量数除
return Vector(a.x / p, a.y / p);
}
int dcmp(double x){//精度三态函数(>0,<0,=0)
if (fabs(x) < eps)return 0;
else if (x > 0)return 1;
return -1;
}
bool operator == (const Point &a, const Point &b){//向量相等
return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
double Dot(Vector a, Vector b){//内积
return a.x*b.x + a.y*b.y;
}
double Length(Vector a){//模
return sqrt(Dot(a, a));
}
double Angle(Vector a, Vector b){//夹角,弧度制
return acos(Dot(a, b) / Length(a) / Length(b));
}
double Cross(Vector a, Vector b){//外积
return a.x*b.y - a.y*b.x;
}
Vector Rotate(Vector a, double rad){//逆时针旋转
return Vector(a.x*cos(rad) - a.y*sin(rad), a.x*sin(rad) + a.y*cos(rad));
}
double Distance(Point a, Point b){//两点间距离
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
double DistanceToLine(Point A, Point M, Point N){//点A到直线MN的距离,Error:MN=0
return fabs(Cross(A - M, A - N) / Distance(M, N));
}
double L;
point P,V;
int k;
LL Find(Point P,Vector V,double H,double len,double len_V){/// 点、方向向量、三角形高度、运动长度、方向向量长度
LL ans=0;
double height=P.y+len*(V.y/len_V);
height/=H;
if(dcmp(V.y)>=0){
ans+=(LL)floor(height);
}
else{
ans+=1-(LL)ceil(height);
}
return ans;
}
int main(){
int t=rd;
while(t--){
scanf("%lf%lf%lf%lf%lf",&L,&P.x,&P.y,&V.x,&V.y);
k=rd;
double len_V=Length(V);
double H=L/2*sqrt(3);
Point PL,PR,VL=Rotate(V,pi*2/3),VR=Rotate(V,-pi*2/3); /// 相对坐标系下的坐标
Point PLmid=Point(-L/4,H/2),PRmid=Point(L/4,H/2);
PL.y=DistanceToLine(P,Point(-L/2,0),Point(0,H));
PL.x=DistanceToLine(P,Point(L/2,0),PLmid);
if(Cross(P-PLmid,Point(L/2,0)-PLmid)<0)
PL.x*=-1;
PR.y=DistanceToLine(P,Point(L/2,0),Point(0,H));
PR.x=DistanceToLine(P,Point(-L/2,0),PRmid);
if(Cross(P-PRmid,Point(-L/2,0)-PRmid)<0)
PR.x*=-1;
double l=0,r=1e11;
double Ans;
while((r-l)/(max(1.0,l))>eps){
double len=(l+r)/2;
//test(len);
LL ans=0;
ans+=Find(P,V,H,len,len_V);
ans+=Find(PL,VL,H,len,len_V);
ans+=Find(PR,VR,H,len,len_V);
if(ans>=k){
//printf("G %lld\n",ans);
Ans=len;
r=len;
}
else{
//printf("L %lld\n",ans);
l=len;
}
}
printf("%.10f\n",Ans/len_V);
}
return 0;
}
/*_________________________________________________________end*/