公式

C - ボーナスの分配 / Bonus Distribution 解説 by kyopro_friends


加算・減算・乗算については、計算をしてから余りを求めても、余りを求めてから計算しても結果は同じになります。除算についても同様に、先に余りを求めてしまっても、乗法逆元を用いることで同じ答えを得られます。(「\(2\) で割る」の代わりに「\(1/2\) を掛ける」としても同じ結果になるのと同様、 \(1/2\) に相当するものを求めて掛けるイメージ)

よって、問題文に与えられた計算式の通りに値を計算していけば良いです。

\(W_{\mathrm{sum}} = \sum_{j=1}^DW_j\) および \(S\) の乗法逆元 \(S_{\mathrm{inv}}\) を事前に計算しておけば、\(T_i=P_i S_{\mathrm{inv}}W_{\mathrm{sum}}\) を求めることは容易です。

前計算に \(O(D+\log\bmod)\)\(T_i\) 及び \(R\) の計算に \(O(N)\) かかるため、全体で \(O(N+D+\log\bmod)\) で問題を解くことができました。

C++ の場合 ACL(AtCoder Library) により提供されている modint クラスを利用すると実装が楽です。

実装例 (C++)

#include<bits/stdc++.h>
#include<atcoder/modint>
using namespace std;
using modint = atcoder::modint998244353;

int main(){
  int n, d;
  cin >> n >> d;
  vector<int>p(n), w(d);
  for(int i=0; i<n; i++) cin >> p[i];
  for(int i=0; i<d; i++) cin >> w[i];

  modint w_sum = 0;
  for(int i=0; i<d; i++){
    w_sum += w[i];
  }
  modint s = 0;
  for(int i=0; i<n; i++){
    s += p[i];
  }
  modint s_inv = 1 / s;
  
  modint r = 1;
  for(int i=0; i<n; i++){
    modint t = p[i] * s_inv * w_sum;
    r *= t;
  }
  cout << r.val() << endl;
}

実装例 (Python)

MOD = 998244353
N, D = map(int, input().split())
P = list(map(int, input().split()))
W = list(map(int, input().split()))
W_sum = sum(W)
S = sum(P)
S_inv = pow(S, -1, MOD)

R = 1
for p in P:
  T = p * S_inv * W_sum % MOD
  R = R * T % MOD

print(R)

投稿日時:
最終更新: