这个世界真奇妙
题意:
n个完全相同的半径为r的小球,最下面的小球底部距离地面高度为h,从t=0开始,每隔1妙下落一个小球,小球之间、小球与地面之间的碰撞都是弹性碰撞,求t秒后每个小球的底部高度,按照从下往上的顺序输出。
Input
The first line of the input contains one integer C (C ≤ 20) indicating the number of test cases. Each of the following lines contains four integers N, H, R, T.
1≤ N ≤ 100.
1≤ H ≤ 10000
1≤ R ≤ 100
1≤ T ≤ 10000
Output
For each test case, your program should output N real numbers indicating the height in meters of the lowest point of each ball separated by a single space in a single line. Each number should be rounded to 2 digit after the decimal point.
这题乍一看觉得好简单,然后被坑了两天
首先是第一个机智点,由于是弹性碰撞,球又全一样,所以交换速度,跟地面撞反向,经常会出现这样碰撞交换速度的情况,称之为弹性碰撞。
第二个机智点,虽然交换速度,但是两个球都是有直径的,一碰就相当于瞬移了d。但是第i个球下面有i-1个球,一个周期向下时瞬移了i-1个d,那么就相当于高度减小i-1个d,就相当于从h下落,向上时同理。这样就可以首先筛出每个球除了周期以外花费的时间,然后算出只考虑单个球的位置,然后由于最终第i个球下面肯定有i-1个球,所以最终高度应该加上i-1个d
然后就是第三个机智点,坑我开了5个vim对拍。考虑两个球碰撞,虽然相当于两个球交换了位置速度不变,但是下面的球编号仍然比上面的球大,所以下面的球最后加的d的数量必然比上面的小,但如果这时候我们查询结果怎么办?这显然不合理。最终的排序应该根据没加d的情况排序,然后再加上对应的d。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
#define mxn 110
int n;
double h,r,t;
double loc[mxn];
const double g=10.0;
int main(){
int cs;
scanf("%d",&cs);
while(cs--){
scanf("%d%lf%lf%lf",&n,&h,&r,&t);
r/=100;
double tt=sqrt(2*h/g)*2;
for(int i=0;i<n;++i){
if(t<=0){
loc[i]=h;
continue;
}
int tem=t/tt;
double res=t-tem*tt;
if(res<=tt/2)
loc[i]=h-0.5*g*res*res;
else{
res=tt*2-res;
loc[i]=h-0.5*g*res*res;
}
t-=1.0;
}
sort(loc,loc+n);
printf("%.2lf",loc[0]);
for(int i=1;i<n;++i)
printf(" %.2lf",loc[i]+i*2*r);
puts("");
}
return 0;
}