CF EDU 109 E - Assimilation IV

E - Assimilation IV

注意到 \(n\) 很小,可以算每个点被至少一个城市覆盖的概率,相加就是期望

本题中直接算点被覆盖的概率并不容易,可以算点没有被任何一个城市覆盖的概率

注意到 \(d(i,j)\) 也很小,最大不超过 \(n+1\)

可以枚举每个点,按距离从小到大给这 \(n\) 个城市排序,设第 \(i\) 个城市与第 \(j\) 个点的距离为 \(dist[i]\)

若第 \(0\) 个城市覆盖不了这个点,则第 \(0\) 个城市要放到后 \(dist[0] - 1\) 个位置

若第 \(1\) 个城市覆盖不了这个点,则第 \(1\) 个城市要放到后 \(dist[1] - 1\) 个位置,但其中有一个位置已经被第 \(0\) 个城市占了(这就是从小到大排序的原因,保证了前一个城市要占的位置是后一个的子集) ,所以只有 \(dist[1]-1-1\) 个位置可以选

...

若第 $ i $ 个城市覆盖不了这个点,则第 \(i\) 个城市有 \(dist[i] - 1-i\) 个位置可以选

求每个城市都覆盖不了这个点的概率,根据乘法原理,为 \(\prod \frac{max(0,dist[i]-1-i)}{n!}\) (若这个点没有位置可选了,说明这个城市一定能覆盖到这个点,所以概率为 \(0\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 21, M = 5e4 + 10;
const int mod = 998244353;
ll fac[N], finv[N];
int d[N][M];
int n, m;

ll qmi(ll a, ll b)
{
	ll ans = 1;
	while(b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans % mod;
}
void presolve()
{
	fac[0] = 1, finv[0] = 1;
	for (int i = 1; i < N; i++)
		fac[i] = fac[i-1] * i % mod;
	finv[N-1] = qmi(fac[N-1], mod - 2);
	for (int i = N - 2; i >= 1; i--)
		finv[i] = finv[i+1] * (i + 1) % mod;
}

int main()
{
	presolve();
	scanf("%d%d", &n, &m);
	ll ans = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%d", &d[i][j]);
	for (int j = 1; j <= m; j++)
	{
		vector<int> dist;
		for (int i = 1; i <= n; i++)
			dist.push_back(d[i][j]);
		sort(dist.begin(), dist.end());
		ll t = 1;
		for (int i = 0; i < n; i++)
			t = t * max(0, dist[i] - 1 - i) % mod;
		ans = (ans + fac[n] - t) % mod;
	}
	ans = (ans + mod) % mod;
	ans = ans * finv[n] % mod;
	printf("%lld\n", ans);
	return 0;
}
posted @ 2022-05-17 22:32  hzy0227  阅读(42)  评论(0编辑  收藏  举报