公式
C - ボーナスの分配 / Bonus Distribution 解説
by
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)
投稿日時:
最終更新:
