HDU7049 Link with Grenade
阿新 • • 發佈:2021-08-11
傳送
這題完全是一道數學題,前幾步初等數學,後幾步高等數學。
對於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)\)
由(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; }