Matrix(组合数学)

题目

Problem - 7113

题解

一开始想的是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\)的总贡献为\(C(n^2-i,n-1) \cdot n\)。再加上全排列,答案为

\[n!(n^2-n)!\sum\limits_{i=1}^{n}{C(n^2-i,n-1) \cdot n} \]

将外面\(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;
		
	}
}
posted @ 2021-09-04 19:09  limil  阅读(190)  评论(0编辑  收藏  举报