2013长沙区域赛的题目
题意:
一个硬币,半径为r,从(x,y)出发,速度(vx,vy)。 在(0,0)位置处有一个固定的,半径为Rm的实心圆。硬币碰到它后会无能量损耗反射。还有一个半径为R的范围,圆心也在(0,0)。硬币开始运动,求硬币有多少时间会呆在范围R内(硬币任何一部分在内都算)。
思路:
我们观察一下硬币与实心圆的圆心距随时间的变化,肯定是从大到小再变大。当然也有可能一直变大,一开始就直接远离。
我们可以三分出圆心距离最近的那个时间,设为limit。
然后在[0,limit]区间内距离都是增大的。我们再二分出,距离达到(R+r)的时间点(也就是将要进入范围R内),再二分出(Rm+r)的时间点(碰撞实心圆),因为反射无能量损耗,运动是对称的,所以两个时间点差值的两倍就是答案。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 100010
#define ll long long
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD=1000000007;
const double EPS=1e-9;
int Rm, R, r, x, y, vx, vy;
double limit;
double dis(double _x,double _y){
return sqrt(_x*_x+_y*_y);
}
double cal(double t){
return dis(t*vx+x,t*vy+y);
}
double getNearest(){
double _l=0.0,_r=INF;
int Time=1<<6;
while(Time--){
double L=(_l+_r)/3.0;
double R=L*2.0;
if(cal(L)<cal(R)) _r=R;
else _l=L;
}
return (_l+_r)/2.0;
}
double find(int target){
double _l=0.0, _r=limit;
int Time=1<<6;
while(Time--){
double mid=(_l+_r)/2.0;
if(dis(mid*vx+x,mid*vy+y)>=target) _l=mid;
else _r=mid;
}
return (_l+_r)/2.0;
}
int main(){
while(~scanf("%d%d%d%d%d%d%d",&Rm, &R, &r, &x, &y, &vx, &vy)){
limit=getNearest();
double a=find(Rm+r), b=find(R+r);
if((a-b)<EPS) puts("0.000");
else printf("%lf\n",(a-b)*2.0);
}
return 0;
}