题意:有$n$个孩子,第$i$个孩子有$k[i]$件想要的礼物,第$j$个礼物为$a[i][j]$,现在随机挑一个孩子,从他想要的礼物里面随机挑一个,然后送给另一个孩子$($这个孩子可以和第一个孩子是同一个人$)$,问你送的这个礼物在后一个孩子愿望单里的概率。

思路:求出每件礼物出现的次数$cnt[]$,挑出第一个孩子的概率为$\frac{1}{n}$,在他的愿望单里挑出一件礼物的概率为$\frac{1}{k[i]}$,挑出另一个孩子的概率也是$\frac{1}{n}$,挑出的第一个孩子的每件礼物$a[i][j]$出现了$cnt[a[i][j]]$次,那么对于第$i$个孩子的第$j$件礼物$a[i][j]$礼物而言,对答案的贡献就是$\frac{cnt[a[i][j]]}{n^{2}*k[i]}$,所以总概率$$p=\sum_{i=1}^{n}\sum_{j=1}^{k[i]}\frac{cnt[a[i][j]]}{n^{2}*k[i]}$$用快速幂取逆元。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long ll;

const int N = 1000010;
const ll mod = 998244353;

ll n, k[N], s[N], cnt[N];
vector<ll> v[N];

ll power(ll a, ll n, ll p)
{
ll ba = a, res = 1;
while (n) {
if (1 == n % 2) res = (res * a) % p;
a = (a * a) % p, n /= 2;
}
return res;
}

int main()
{
scanf("%lld", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld", &k[i]);
for (int j = 1; j <= k[i]; j++) {
ll a;
scanf("%lld", &a);
cnt[a]++, v[i].push_back(a);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < k[i]; j++) s[i] += cnt[v[i][j]];
}
ll res = 0;
for (int i = 1; i <= n; i++) {
ll tp = ((n * n) % mod * k[i] % mod) % mod;
ll inv = power(tp, mod - 2, mod);
res = (res + (s[i] * inv) % mod) % mod;
}
printf("%lld\n", res);
return 0;
}