[ICPC 2024 Nanjing R] Bingo
先给序列排序,权值相同的钦定标号前的更小。转化成 \(Ans\le a_k\) 的情况,等价于 \(k\) 个 \(1\),\(nm-k\) 个 \(0\) 放入 \(n\times m\) 的矩阵,至少有一行或者一列是全 \(1\)。考虑其反面,钦定共 \(i\) 行 \(j\) 列都是 \(1\) 然后容斥,那么有:
\[f(k)=k!(nm-k)!\sum_{i=0}^n\sum_{j=0}^m(-1)^{i+j}\binom ni\binom mj\binom{nm-nj-im+ij}{k-nj-im+ij}
\]
令 \(s=nj+im-ij\),则 \(\binom{nm-nj-im+ij}{k-nj-im+ij}=\binom{nm-s}{k-s}=(nm-s)!/\left((k-s)!(nm-k)!\right)\)
令 \(g(s)=\sum_{i=0}^n\sum_{j=0}^m(-1)^{i+j}\binom ni\binom mj(nm-s)!\),\(h(s)=1/s!\),那么 \(f(k)=k!\sum_s g(s)h(k-s)\),卷积即可求出所有的 \(f(k)\),答案即:
\[\sum_{i=1}^{nm}(f(i)-f(i-1))a_i
\]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}return x*f;
}
const int N=8e5+10,mod=998244353,G=3,I=332748118,maxn=2e5;
void Add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void Sub(int &x,int y){x-=y;if(x<0)x+=mod;}
int qpow(int a,int n)
{int ans=1;while(n){if(n&1)ans=1ll*a*ans%mod;a=1ll*a*a%mod;n>>=1; }return ans;
}
namespace poly
{int r[N];void ntt(vector<int> &a,int lim,int k){for(int i=0;i<lim;i++)if(i<r[i])swap(a[i],a[r[i]]);for(int mid=1;mid<lim;mid<<=1){int wn=qpow(k?G:I,(mod-1)/(mid<<1));for(int R=mid<<1,j=0;j<lim;j+=R){int w=1;for(int t=0;t<mid;t++,w=1ll*w*wn%mod){int x=a[j+t],y=1ll*w*a[j+mid+t]%mod;a[j+t]=(x+y)%mod,a[j+mid+t]=(x-y+mod)%mod;}}}}vector<int> mul(vector<int> f,vector<int> g){int n=f.size()-1,m=g.size()-1,lim=1,l=0;while(lim<=n+m)lim<<=1,l++;for(int i=0;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));f.resize(lim),g.resize(lim);ntt(f,lim,1),ntt(g,lim,1);vector<int> h(lim);for(int i=0;i<lim;i++)h[i]=1ll*f[i]*g[i]%mod;ntt(h,lim,0);int inv=qpow(lim,mod-2);for(int i=0;i<=lim;i++)h[i]=1ll*h[i]*inv%mod;while(!h.empty()){if(!*--h.end())h.pop_back();else break;}return h;}
}
using poly::mul;
int a[N],g[N],fac[N],ifac[N];
int binom(int n,int m){return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
void sol()
{int n=read(),m=read();for(int i=1;i<=n*m;i++)a[i]=read();sort(a+1,a+n*m+1);vector<int> f(n*m+1),g(n*m+1);for(int i=0;i<=n;i++)for(int j=0;j<=m;j++){int s=n*j+i*m-i*j;if((i+j)&1)Sub(g[s],1ll*binom(n,i)*binom(m,j)%mod*fac[n*m-s]%mod);else Add(g[s],1ll*binom(n,i)*binom(m,j)%mod*fac[n*m-s]%mod);}for(int i=0;i<=n*m;i++)f[i]=ifac[i];f=mul(f,g);for(int i=0;i<=n*m;i++)f[i]=1ll*f[i]*ifac[n*m-i]%mod*fac[i]%mod*fac[n*m-i]%mod;for(int i=0;i<=n*m;i++)f[i]=(fac[n*m]-f[i]+mod)%mod;for(int i=n*m;i>=1;i--)Sub(f[i],f[i-1]); int Ans=0;for(int i=1;i<=n*m;i++)Add(Ans,1ll*f[i]*a[i]%mod);printf("%d\n",Ans);
}
int main()
{fac[0]=1;for(int i=1;i<=maxn;i++)fac[i]=1ll*fac[i-1]*i%mod;ifac[maxn]=qpow(fac[maxn],mod-2);for(int i=maxn-1;i>=0;i--)ifac[i]=1ll*(i+1)*ifac[i+1]%mod; int T=read();while(T--)sol();return 0;
}