Matrix(組合數學)
阿新 • • 發佈:2021-09-04
題目
題解
一開始想的是dp,但是需要\(dp[i][j]\)代表在\(n \times i\)的方格中放入\(j\)個數使得每列都至少有一個數的方案數,這樣答案就是
\[n!(n^2-n)!\sum\limits_{i=1}^{n}{i\cdot dp[i][n] \cdot C(n,i)} \]但是計算dp複雜度是\(O(n^3)\),不可做。
突破點是分別計算1~n每個數的貢獻。對於數\(i\),當它所在行的其他數都大於\(i\)時對答案有1的貢獻,這樣的局面有\(C(n^2-i,n-1) \cdot n\),乘\(n\)是\(i\)在一行有\(n\)個位置可以選。此時\(i\)
將外面\(n!(n^2-n)!\)移進去可以消掉很多項,這樣就不會T。
#include <bits/stdc++.h> #define endl '\n' #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0) #define mp make_pair #define seteps(N) fixed << setprecision(N) typedef long long ll; using namespace std; /*-----------------------------------------------------------------*/ ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} #define INF 0x3f3f3f3f const int N = 2.5e7 + 10; const int M = 998244353; const double eps = 1e-5; ll fact[N], rfact[N], inv[N]; inline ll qpow(ll a, ll b, ll m) { ll res = 1; while(b) { if(b & 1) res = (res * a) % m; a = (a * a) % m; b = b >> 1; } return res; } int main() { IOS; fact[0] = 1; for(int i = 1; i < N; i++) { fact[i] = fact[i - 1] * i % M; } int t; cin >> t; while(t--) { int n; cin >> n; ll ans = 0; ll tn = n * n - n; ll pw = 1; for(int i = 1; i <= n; i++) { ans = (ans + fact[n * n - i] * n % M * n % M * pw % M) % M; pw = pw * tn % M; tn--; } cout << ans << endl; } }