传送
这题完全是一道数学题,前几步初等数学,后几步高等数学。
对于3d空间,都能想到像橘子瓣儿一样取出一个薄片,算出那个不会被炸到的角度占\([0,\pi]\)的比例.记和\(z\)轴正向的夹角为\(\varphi\),用初中物理知识可以得到
由此可见,\(\cos\varphi\)是一个有理数,那么\(\varphi\)也是一个有理数的概率很小,因此直接求角的方法似乎行不通。
回到三维空间,我们根据角度画出单位球,那么会被炸到的地方就是一个球冠,因此可以用球冠的表面积比上整个球的表面积\(4\pi R^2\),就能求出被炸到的概率。
那球冠的表面积怎么求?有公式,背住就更好。背不住可以用积分:一种是用元素法,但我元素法学的不太好,遂用第一类曲面积分(然而早忘了,现复习的),我们要求的,无非是
\[\iint\limits_\sum \textrm{d}S \]其中\(\textrm{d}S=R^2\sin\varphi\textrm{d}\varphi\textrm{d}\theta\),那么
\[\iint\limits_\sum \textrm{d}S=R^2 \int_{0}^{\varphi_0}\sin\varphi\textrm{d}\varphi\int_0^{2\pi}\textrm{d}\theta \]这个当然好解,解出来是\(2\pi R^2(1-\cos\varphi_0)\),这样就能算出来不被炸到的概率:
\[P=1-\frac{2\pi R^2(1-\cos\varphi_0)}{4\pi R^2}=\frac{1+\cos\varphi_0}{2} \]由(1)可知,\(\cos\varphi_0\)是个有理数,因此这样算出来的概率就是有理数。
最后别忘了判断一定会被炸到和一定炸不到的情况,即分别让(1)式右侧\(\geqslant 1\)和\(\leqslant -1\),得出两个不等式。而且因为题目给的\(v_0,t,R\)范围不大于\(100\),正好就可以在long long范围内进行比较大小。
#include<bits/stdc++.h>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
In ll read()
{
ll ans = 0;
char ch = getchar(), las = ' ';
while(!isdigit(ch)) las = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(las == '-') ans = -ans;
return ans;
}
In void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
In ll quickpow(ll a, ll b)
{
a %= mod;
ll ret = 1;
for(; b; b >>= 1, a = a * a % mod)
if(b & 1) ret = ret * a % mod;
return ret;
}
In ll solve(ll t, ll v, ll r)
{
ll tp1 = v * v * t * t + 25LL * t * t * t * t - r * r;
ll tp2 = 10LL * v * t * t * t;
if(tp2 + tp1 <= 0) return 0;
if(tp1 - tp2 >= 0) return 1;
return ((tp1 % mod + mod) % mod * quickpow(tp2, mod - 2) % mod + 1) * quickpow(2, mod - 2) % mod;
}
int main()
{
int T = read();
while(T--)
{
ll t = read(), v = read(), r = read();
write(solve(t, v, r)), enter;
}
return 0;
}