題意:聖誕老人收到一些信件來自n個不一樣的小朋友這年,固然,每一個孩子都想要從聖誕老人那獲得一些禮物,尤爲,第i個小朋友想要ki個不一樣的禮物中的一個做爲他的禮物,一些禮物可能被多個小孩所擁有。ios
聖誕老人很忙碌,因此他想要新年機器人去選擇一些禮物給孩子,不幸的是,機器人算法出了一些Bug,爲了選擇一些禮物給孩子,機器人執行以下的操做: 1.等機率地從n個孩子中選擇孩子x 2.從第x個小孩想要的kx個禮物中等機率地選出y禮物 3.等機率地選擇一個小孩z去接受這個禮物 (x, y, x)被叫作機器人的一種選擇 若是小孩z列出的禮物中存在y禮物,那麼這個選擇就是有效的。 計算這個選擇有效的機率算法
輸入: 第一行表示n個小孩 接下來n行,第i行表示第i個小孩想要的聖誕禮物列表,ki, ai1, ai2, ... aiki, 一個禮物在同一個列表裏不會出現屢次spa
輸出: 打印機器人有效選擇的機率,把這個機率表示爲不可約分數$\frac{x}{y}$,你必須打印$x \cdot{y}^{-1} mod 998244353$code
分析:題目的意思是說有n個小孩子,每一個孩子有ki件禮物是他們想要的,如今隨機地挑出一個孩子去接受這個禮物,而且這個禮物也是存在他想要的禮物單裏的詢問這個機率 假設咱們如今挑出來一個孩子x,挑出他的機率爲1 / n,從他的願望單裏選出一個禮物,機率變爲1 / n * 1 / k[x],再挑一個孩子,而且符合的機率爲:1/n * 1/k[x] * 該禮物的數量(全部願望單裏) / n,這樣就能夠求得這個機率,而後把全部機率相加,能夠獲得以下的公式 $\frac{1}{n^2}*\sum_{i = 1}^{n}(\frac{\sum cnt[i][j]}{k[i]})$ 輸出要求咱們先把這個機率化成不可約的分數x / y,而後求x / y mod 998244353,這個能夠採用快速冪求逆元,快速冪求逆元的做用就是把x / y mod p這種形式的東西變成x * q mod p,即把這個除法化成乘法,而且它們相模的值相等 由於,在計算機中除法變成乘法會變得好不少 這是數論的東西,想弄懂這道題必需要有前綴知識:快速冪取模和快速冪求逆元string
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; using LL = long long; const int mod = 998244353; const int N = 1e6 + 5; vector<int> list[N]; int k[N]; //記錄禮物數量 int cnt[N]; //快速模 LL qmi(int a, int b, int p) { LL res = 1; while (b) { if (b & 1) res = res * a % p; a = a * (LL)a % p; b >>= 1;//b右移一位 } return res; } //費馬小定理 //y的模mod的乘法逆元 int Fermat(int y) { return qmi(y, mod - 2, mod); } int main() { //n個小孩 int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", &k[i]); list[i].resize(k[i] + 1); for (int j = 1; j <= k[i]; ++j) { scanf("%d", &list[i][j]); ++cnt[list[i][j]]; } } LL res = 0; //計算機率 //只需求1/k[x] * cnt便可 for (int i = 1; i <= n; ++i) { LL cur = 0; for (int j = 1; j <= k[i]; ++j) cur += cnt[list[i][j]]; //求k[i]模mod的乘法逆元 res += ((cur % mod) * Fermat(k[i])) % mod; } //再乘以1 / n * n res = ((res % mod)) * Fermat((1ll * n * n) % mod) % mod; printf("%lld\n", res); return 0; }