被教育场
题意:先等概率选一个人,再从他想要礼物里等概率选一个,再独立于前两次选择,选一个人,他想要的礼物也被选中,则该组合有效,求组合有效的分数概率(模意义下)
玩一下两个样例应该就能出来知道咋算,虽然我第一个样例是跑了两重循环得出 7/8,拼凑起来才勉强理解的题意。
但知道咋算不一定会code啊。
我就是啊。
模拟了分数的加法乘法运算,通分约分,肯定要WA啊,因为到后面分子分母越来越大存不下。
但实际上,两个分数在某个模数意义下相加可以直接转化,即 x/y+u/v == x*inv(y) +u*inv(y)
证明我也不会呀
这辈子不可能去证明的
理解还是好理解的
此处由于模数是质数,直接由费马小定理得到逆元来算就行了
1 #include <bits/stdc++.h> 2 3 #ifndef ONLINE_JUDGE 4 #define debug(x) cout << #x << ": " << x << endl 5 #else 6 #define debug(x) 7 #endif 8 9 using namespace std; 10 typedef long long ll; 11 const int MAXN=1e6+7; 12 const int INF=0x3f3f3f3f; 13 const int MOD=998244353; 14 15 16 vector<int>a[MAXN]; 17 int cnt[MAXN]; 18 19 ll quick(ll x,ll n) //¿ìËÙÃÝ x^n 20 { 21 ll res=1; 22 while(n) 23 { 24 if(n&1) res=(res*x)%MOD; 25 x=(x*x)%MOD; 26 n>>=1; 27 } 28 return res; 29 } 30 31 ll inv(ll a) 32 { 33 return quick(a,MOD-2); 34 } 35 36 int main() 37 { 38 ios::sync_with_stdio(false); 39 cin.tie(0); 40 int n; 41 cin>>n; 42 for(int i=0;i<n;++i) 43 { 44 int k; 45 cin>>k; 46 while(k--) 47 { 48 int tt; 49 cin>>tt; 50 a[i].push_back(tt); 51 cnt[tt]++; 52 } 53 } 54 ll ans=0; 55 for(int i=0;i<n;++i) 56 { 57 int q=a[i].size(); 58 ll tmp=0; 59 for(auto u:a[i]) 60 tmp+=cnt[u]; 61 ll cur=inv(1ll*n*n%MOD*q%MOD)*tmp%MOD; 62 ans+=cur; 63 debug(ans); 64 debug(tmp); 65 ans%=MOD; 66 } 67 cout<<ans<<endl; 68 return 0; 69 }View Code