1. 程式人生 > 其它 >題解 CF1525E Assimilation IV

題解 CF1525E Assimilation IV

我果然一點組合數學都不會。

\(n\) 個城市,\(m\) 個點,每秒等概率隨機點亮一個未點亮的城市,被點亮的城市在此後第 \(j\) 秒能照亮距離 \(j+1\) 以內的點,求最後照亮點的期望。

首先轉換成每個點的概率和是老套路了,然後就是在排列中限制了一些點要在某個之前出現。
但是直接計算會有重複,因為可能有多個城市照亮了這個點。
那麼就正難則反,考慮所有點都不照亮,但這個限制似乎會互相影響。
實際上只要按照能填的端點從後往前排個序再乘法原理就可以了,因為排了序之後前面填上的就一定會讓後面填上的能填的位置數量減少 \(1\),這應該是一個很常見的技巧了。

程式碼
#include <algorithm>
#include <iostream>
#include <vector>
#define int long long
const int M = 50005, P = 998244353;
int n, m, fac = 1, inv, ans, x;
std::vector<int> d[M];
int Pow(int a, int b) {
    int an = 1;
    for ( ; b; b >>= 1, a = a * a % P) 
        if (b & 1) an = an * a % P;
    return an;
}
signed main() {
    std::cin >> n >> m;
    for (int i = 1; i <= n; i++) 
        for (int j = 1; j <= m; j++)
            std::cin >> x, d[j].push_back(x-1);
    for (int i = 1; i <= m; i++) std::sort(d[i].begin(), d[i].end());
    for (int i = 1; i <= n; i++) fac = fac * i % P;
    inv = Pow(fac, P-2);
    for (int i = 1; i <= m; i++) {
        int an = 1;
        for (int j = 0; j < (int)d[i].size(); j++)
            an = an * (d[i][j]-j) % P;
        ans = (ans + (1 - an*inv % P + P) % P) % P;
    }
    std::cout << ans;
}