Maths
2020 沈阳 I. Rise of Shadows
-
思路:
-
首先 v H = 2 π H M , v M = 2 π M v_H=\dfrac{2\pi}{HM},v_M=\dfrac{2\pi}{M} vH=HM2π,vM=M2π,每一次时针和分针重合的间隔时间计算为
Δ T ( v M − v H ) = 2 π Δ T = H M H − 1 \Delta T(v_M-v_H)=2\pi\\ \Delta T=\dfrac{HM}{H-1} ΔT(vM−vH)=2πΔT=H−1HM
每次在两针重合前后需要偏转到 α = 2 π A H M \alpha=\dfrac{2\pi A}{HM} α=HM2πA 角度,此时需要时间为
∣ t ′ ∣ ( v M − v H ) = α ∣ t ′ ∣ = A H − 1 |t'|(v_M-v_H)=\alpha\\ |t'|=\dfrac{A}{H-1} ∣t′∣(vM−vH)=α∣t′∣=H−1A
于是每个整数时刻(“integal moments”)即为所有满足 ( k H M − A H − 1 , k H M + A H − 1 ) , k ∈ [ 0 , H − 1 ] \left(\dfrac{kHM-A}{H-1},\dfrac{kHM+A}{H-1} \right),k\in[0,H-1] (H−1kHM−A,H−1kHM+A),k∈[0,H−1] 内的范围在 [ 0 , H M ) [0,HM) [0,HM) (这个左闭右开的问题可以将两端情况合并到一个重合点)内的整数。 -
需要将问题转化为求 − A ≤ t ( H − 1 ) ( m o d H M ) ≤ A , t ∈ [ 0 , H M ) -A\le t(H-1)\pmod {HM}\le A,t\in [0,HM) −A≤t(H−1)(modHM)≤A,t∈[0,HM),由于要求整数,便可以把范围边界约到“整数”(可取整)。又因为若 a , b , c a,b,c a,b,c 为任意 3 3 3个整数, m m m 为正整数,且 ( m , c ) = 1 (m,c)=1 (m,c)=1,则当 a c ≡ b c ( m o d m ) ac\equiv bc\pmod {m} ac≡bc(modm)时,有 a ≡ b ( m o d m ) a\equiv b\pmod {m} a≡b(modm)。所以为了满足互质,两边同除 g = gcd ( H − 1 , H M ) g=\gcd{(H-1,HM)} g=gcd(H−1,HM),得到
− A g ≤ t ∗ H − 1 g ( m o d H M g ) ≤ A g , t ∈ [ 0 , H M g ] {-A\over g}\le t*{H-1\over g}\pmod{{HM\over g}}\le {A\over g},\quad t\in [0,{HM\over g}] g−A≤t∗gH−1(modgHM)≤gA,t∈[0,gHM]
此时正负半轴都只有 1 , 2 , . . . , A g 1,2,...,{A\over g} 1,2,...,gA 个解,算上重合时的情况,共有 2 ∗ A g + 1 2*\dfrac{A}{g}+1 2∗gA+1 个解。还原到 [ 0 , H M ) [0,HM) [0,HM) 上便有 g ∗ ( 2 ∗ A g + 1 ) g*(2*\dfrac{A}{g}+1) g∗(2∗gA+1) 个解。 -
注意当 A = H M 2 A=\dfrac{HM}{2} A=2HM 时,两个相邻重合情况前后重叠,于是 [ 0 , H M ) [0,HM) [0,HM) 内的所有整数时刻都满足条件,需要特判。
#include<bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = (a); i <= (b); i++) #define per(i, a, b) for(int i = (a); i >= (b); i--) #define ll long long #define db double #define VI vector<int> #define PII pair<int, int> #define Pi 3.141592653589793 const int INF = 0x7fffffff; const int N = 1e5 + 5; const db eps = 1e-10; ll H, M, A; db h, m, a; int main(){ cin >> H >> M >> A; h = H, m = M, a = A; if(A * 2 == H * M) cout << H * M << endl; else{ int x = __gcd(H * M, H - 1); cout << x * (2 * (A / x) + 1) << endl; } } /* 5 5 4 9 3 5 1 3 */
-
2020 上海 I. Sky Garden
-
思路:由于需要走最短距离,当圆上两点角度相差大于 θ \theta θ 时,经过原点会更优。计算得到
θ r < 2 r ∴ θ < 2 ≈ 144 ° \theta r<2r\\ \therefore \theta<2\approx144° θr<2r∴θ<2≈144°
于是可以固定一个轴线方向的点,最后 ∗ 2 m *2m ∗2m 即可。我们统计一圈中角度相差在 θ \theta θ 内的点一边有 A A A 个,两边就有 2 A 2A 2A 个。分成四种情况讨论:- 当角度相差 θ < 2 \theta<2 θ<2 时,两点之间路程为 a b s ( R − r ) + min ( R , r ) θ abs(R-r)+\min(R,r)\theta abs(R−r)+min(R,r)θ,其中弧上路程 min ( R , r ) θ \min(R, r)\theta min(R,r)θ 需要走 2 ∗ ( 1 + 2 + . . . + A ) 2*(1+2+...+A) 2∗(1+2+...+A) 个(因为有左右两边),半径差路程 a b s ( R − r ) abs(R-r) abs(R−r) 需要走 2 A 2A 2A 个。但是,当 r = R r=R r=R,即在同一个圆上时, 两点被重复算了两遍;而在不同圆上,由于我们两次循环半径都不同,枚举的点没有重复。于是在同一圆上需要 / 2 /2 /2 。
- 当角度相差 θ > 2 \theta>2 θ>2 时,两点需要经过原点共有 2 m − 2 A − 1 2m-2A-1 2m−2A−1 个点。同理当 r = R r=R r=R 时需要 / 2 /2 /2 。
- 当角度相差 θ = 0 \theta=0 θ=0 时,不同半径之间只需要加上半径差
最后每圈有 2 m 2m 2m 个点,而且当 m ≠ 1 m\ne 1 m=1 时,由于原点存在,还需要加上所有圆上点到原点的距离即可。
#include<bits/stdc++.h> #define rep(i, a, b) for(int i = a; i <= b; i++) #define db double #define ll long long #define Pi 3.141592653589793 using namespace std; int n, m, A; db ans = 0, per; int main() { cin >> n >> m; A = floor(2.0 * m / Pi); per = Pi / (db)m; rep(R, 1, n){ rep(r, R, n){ db tmp = 0; //theta < 2 tmp += min(r, R) * per * (A * (1 + A) / 2.0) * 2; //theta > 2 tmp += (R + r) * (2 * m -2 * A - 1); if(r == R) tmp /= 2.0; //只有在同圆内才有重复计算 //theta == 0 tmp += abs(R - r); //theta < 2 tmp += abs(R - r) * 2 * A; ans += tmp; } } ans *= (2 * m); if(m != 1) ans += (n * (n + 1) / 2.0) * (2 * m); //原点 printf("%.9lf", ans); } /* 2 3 175.4159265359 2 4 302.2477796076938 2 5 468.4955592153876 */