ICPC数学题——补题(更新中)

Maths

2020 沈阳 I. Rise of Shadows

  • Rise of Shadows

  • 思路

    1. 首先 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(vMvH)=2πΔT=H1HM
      每次在两针重合前后需要偏转到 α = 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(vMvH)=αt=H1A
      于是每个整数时刻(“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] (H1kHMA,H1kHM+A),k[0,H1] 内的范围在 [ 0 , H M ) [0,HM) [0,HM) (这个左闭右开的问题可以将两端情况合并到一个重合点)内的整数。

    2. 需要将问题转化为求 − 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) At(H1)(modHM)At[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} acbc(modm)时,有 a ≡ b ( m o d m ) a\equiv b\pmod {m} ab(modm)。所以为了满足互质,两边同除 g = gcd ⁡ ( H − 1 , H M ) g=\gcd{(H-1,HM)} g=gcd(H1,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}] gAtgH1(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 2gA+1 个解。还原到 [ 0 , H M ) [0,HM) [0,HM) 上便有 g ∗ ( 2 ∗ A g + 1 ) g*(2*\dfrac{A}{g}+1) g(2gA+1) 个解。

    3. 注意当 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

  • Sky Garden

  • 思路:由于需要走最短距离,当圆上两点角度相差大于 θ \theta θ 时,经过原点会更优。计算得到
    θ r < 2 r ∴ θ < 2 ≈ 144 ° \theta r<2r\\ \therefore \theta<2\approx144° θr<2rθ<2144°
    于是可以固定一个轴线方向的点,最后 ∗ 2 m *2m 2m 即可。我们统计一圈中角度相差在 θ \theta θ 内的点一边有 A A A 个,两边就有 2 A 2A 2A 个。分成四种情况讨论:

    1. 当角度相差 θ < 2 \theta<2 θ<2 时,两点之间路程为 a b s ( R − r ) + min ⁡ ( R , r ) θ abs(R-r)+\min(R,r)\theta abs(Rr)+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(Rr) 需要走 2 A 2A 2A 个。但是,当 r = R r=R r=R,即在同一个圆上时, 两点被重复算了两遍;而在不同圆上,由于我们两次循环半径都不同,枚举的点没有重复。于是在同一圆上需要 / 2 /2 /2
    2. 当角度相差 θ > 2 \theta>2 θ>2 时,两点需要经过原点共有 2 m − 2 A − 1 2m-2A-1 2m2A1 个点。同理当 r = R r=R r=R 时需要 / 2 /2 /2
    3. 当角度相差 θ = 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
    */
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值