ベスパリブ

プログラミングを主とした日記・備忘録です。ベスパ持ってないです。

SoundHound Inc. Programming Contest 2018 -Masters Tournament- のC問題解いた

問題:SoundHound Inc. Programming Contest 2018 -Masters Tournament- C - Ordinary Beauty

  • 1~nの目のサイコロがある
  • m回サイコロを振って、出た目を数列 (a_1, a_2, ... , a_{m})とする
  • 数列の隣り合う2項の差がdの個数を、その数列の美しさとする
  • 数列の美しさの期待値 Eを求めよ

みたいな問題。

解説

  • 隣り合う2項は m-1個ある
    •  (a_1, a_2), (a_2, a_3), ...,(a_{m-1}, a_m) m-1
  • 解説PDFにあるように、「期待値の線形性より、m-1通りそれぞれにおいて、差の絶対値がdである確率を求めて、全部足せばよい」
  • ある隣り合う2項の美しさを x_i、その発生確率を P_iとすると、ある隣り合う2項の美しさの期待値は \Sigma_i{x_i P_i}である。
    •  i=0,1
    •  x_0 = 0
    •  x_1=1
  • 求めたい数列の期待値 Eは、 E=(m-1)\Sigma_i{x_iP_i}
    •  x_0=0より、 E = (m-1)x_1 P_1となる。
    • さらに x_1=1より、 E = (m-1)P_1となる。
  • なので発生確率 P_1を求めればよい
  • 隣り合う2項を (a, b)と表したとき、この a bの差の絶対値が dである(すなわち x_1=1である)発生確率 P_1を求めたい。
    •  d = 0のとき
      • 美しさの条件を満たすのは
        •  (1,1),(2,2),...,(n,n) n通り
      • よって、発生確率 P_1 \frac{n}{n^{2}} = \frac{1}{n}(分母の n^{2}は、aが n通り、bが n通りだから)
    •  d\neq0のとき
      • 美しさの条件を満たすのは
        •  (1,1+d), (2, 2+d), ..., (n-d, n)
        •  (1+d, 1), (2+d, 2), ..., (n, n-d)
        •  2(n-d)通り
      • よって発生確率 P_1は、 \frac{2(n-d)}{n^{2}}
  • これで求める期待値 E=(m-1)P_1が求まった。

実装

C++での解法です。

#include <bits/stdc++.h>
#define _USE_MATH_DEFINES  // M_PI等のフラグ
#define MOD 1000000007
#define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define intceil(a,b) (a+(b-1))/b
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<long,long>;
const long long INF = LONG_LONG_MAX - 1001001001;
void chmax(int& x, int y) { x = max(x,y); }
void chmin(int& x, int y) { x = min(x,y); }


void solve() {
    // 隣り合う2項はm-1通りある
    // 2項(a,b)のa,bの絶対値の差がdである確率を求めて、(m-1)倍すればよい
    ll n, m, d; cin >> n >> m >> d;
    double ans;
    if (d==0) {
        // (1,1),...(n,n)のn通り
        ans = (double)n/pow(n,2);
        ans *= (m-1);
    }
    else {
        // (1, 1+d), (2, 2+d), ..., (n-d, n)
        // (1+d, 1), (2+d, 2), ..., (n, n-d) の2(n-d)通り
        ans = (double)2*(n-d)/pow(n,2);
        ans *= (m-1);
    }
    printf("%.10lf", ans);
}


int main() {
    solve();
    return 0;
}