hdu-7113 Matrix 组合数学(计算贡献

本文探讨如何计算n×n矩阵中,从第1行到第n行,每行最小值形成的集合A与[1,n]的交集集合S的元素和Σ|S|,利用组合数学和全排列原理,通过递推公式简化计算过程,最终给出O(nlog(n))的时间复杂度解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Matrix
题意:一个 n × n n\times n n×n 的矩阵,每个位置放置一个数,数的范围 ∈ [ 1 , n 2 ] \in [1,n^2] [1,n2],从第 1 1 1 行到第 n n n 行,每行的最小值形成一个集合 A = A= A= { a 1 , a 2 , a 3 . . . a n a_1,a_2,a_3...a_n a1,a2,a3...an},与集合 B = B= B= { 1 , 2 , 3 , . . . . n 1,2,3,....n 1,2,3,....n} 的交集生成集合 S S S ∣ S ∣ |S| S 表示集合 S S S 所有数之和,求所有的 S S S 集合的 ∣ S ∣ |S| S 之和。
思路:
每一个矩阵可以生成一个集合 A = A= A= { a 1 , a 2 , a 3 . . . a n a_1,a_2,a_3...a_n a1,a2,a3...an},与集合 B B B 取交集进而生成一个集合 S S S
我们考虑计算贡献
先看 1 1 1,无论它在矩阵的哪个位置始终会生成到集合 A A A,然后看 2 2 2,它只有与 1 1 1 在同一行的时候才无法产生贡献,看 3 3 3,只有 1 , 2 1,2 1,2 的位置会对 3 3 3 产生贡献有影响,然后我们可以发现,对于 i ∈ ( 1 , 2 , 3 , . . . n ) i \in (1,2,3,...n) i(1,2,3,...n),只有 < i <i <i i − 1 i-1 i1个数的位置会对 i i i 产生的贡献有影响。
一开始我考虑用所有的情况 − - 无法产生贡献的情况去计算答案( n = 2 n=2 n=2的时候过样例了以为写对了,结果一直wa,写的代码比较烂,有时候还T),然后发现情况比较复杂,如果考虑直接计算产生贡献的情况其实是不复杂的。
我们先选定 i i i ,然后给在 n 2 − i n^2-i n2i 个 数中选 n − 1 n-1 n1 个数来和它在一排( C n 2 − i n − 1 C_{n^2-i}^{n-1} Cn2in1),然后乘以这一行的全排列 A n n A_n^n Ann,然后乘以 C n 1 C_n^1 Cn1,确定这行在哪,然后再安排剩下的 n 2 − n n^2-n n2n 个数。
首先选出 n n n 个数, C n 2 − n n C_{n^2-n} ^ n Cn2nn 在一行,然后全排列
然后继续选 n n n 个数, C n 2 − 2 n n C_{n^2-2n} ^n Cn22nn 在一行,然后全排列

然后我们把它写成分数的形式就可以发现可以化简
n ! ( n 2 − n ) ! n ! ( n 2 − 2 n ) ! × n! \frac{(n^2-n)!}{n!(n^2-2n)!} \times n!n!(n22n)!(n2n)!× n ! ( n 2 − 2 n ) ! n ! ( n 2 − 3 n ) ! × n! \frac{(n^2-2n)!}{n!(n^2-3n)!} \times n!n!(n23n)!(n22n)!× n ! ( n 2 − 3 n ) ! n ! ( n 2 − 4 n ) ! × n! \frac{(n^2-3n)!}{n!(n^2-4n)!} \times n!n!(n24n)!(n23n)!× n ! 2 n ! n ! n ! × n! \frac{2n!}{n!n!} \times n!n!n!2n!× n ! n ! n ! 0 ! n! \frac{n!}{n!0!} n!n!0!n!
然后我们可以发现,每一项分子分母都有 n ! n! n!,就都约掉了,分母的一部分可以和后一项分子约掉,最后剩下 ( n 2 − n ) ! {(n^2-n)!} (n2n)!

举个例子简化这个过程:比如有 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5 5 5 5 个数,求全排列,其中 3 3 3 是特殊的,我们先安排3的位置,有 5 5 5个位置可以选择,然后考虑其他的数 C 4 1 C_4^1 C41,再选一个 C 3 1 C_3^1 C31,继续 C 2 1 C_2^1 C21 C 1 1 C_1^1 C11,最后得到 A 5 5 A_5^5 A55
所以我们得到公式
∑ i = 1 i = n C n 2 − i n − 1 A n n C n 1 ( n 2 − n ) ! \sum_{i=1}^{i=n}C_{n^2-i}^{n-1}A_n^nC_n^1(n^2-n)! i=1i=nCn2in1AnnCn1(n2n)!
(其实好像也可以这么理解,安排第一行和它的位置之后,剩下的数进行全排列。

我们预处理一下所有的阶乘,注意计算组合数的时候就没必要用 f o r for for 来计算,直接用阶乘+逆元求得,不然也会 T L E TLE TLE
复杂度: O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))
code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 5e3 + 9;
const int maxm = 2e7 + 5e6 + 9;
const int mod = 998244353;
ll A[maxm];
ll n;
ll q_pow(ll a, ll b){
    ll ans = 1;while(b){
        if(b & 1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;
    }return ans;
}
ll zh(ll n, ll m)
{
    ll ans1 = A[n] * q_pow(A[n-m],mod-2) % mod;
    return ans1 * q_pow(A[m], mod-2ll) % mod;
}
void work()
{
    scanf("%lld", &n);
    ll ans = 0;
    ll tmp = n * n;
    ll tt = A[tmp-n] * n % mod;// 观察可以发现这项可以提出来最后算
    for(ll i = 1; i <= n; ++i) 
    {
        ll x = zh(tmp-i, n-1) * A[n] % mod;
        ans = (ans + x % mod) % mod;
    }
    printf("%lld\n", ans*tt%mod);
}

int main()
{
    A[0] = 1;
    for(ll i = 1; i <= maxm - 9; ++i) A[i] = A[i-1] * i % mod;
    int TT;scanf("%d",&TT);while(TT--)
    work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值