[題目描述]:
給出一個 \(n×m\) 大小的矩形,每個位置可以填上$ [1,c]$中的任意一個數,要求填好后任意兩行互不等價且任意兩列互不等價,兩行或兩列等價當且僅當對應位置完全相同,求方案數 。
\(n,m\le 5000\)
確實是一道神仙題。
對這種行列都有限制的題我們可以先只考慮一邊。
我們先只考慮讓行之間互不等價,一個\(n行m列\)且行互不等價的矩形的方案數為\((C^m)^{\underline{n}}\)。
我們設\(g(m)\)表示行互不等價的情況下,\(m\)列的矩形的方案數。\(g(m)=(C^m)^{\underline{n}}\)。
我們設\(f(m)\)表示行和列都分別互不等價的情況下,\(m\)列的矩形的方案數,也就是我們要的答案。
則:
\[g(m)=\sum\limits_{i=0}^m\begin{Bmatrix}m\\i \end{Bmatrix}f(i) \]
這個式子的意義就是我們枚舉\(m\)列分成了\(i\)個互不等價的集合,再將這\(m\)列分配到這些集合中去。
由斯特林反演得到:
\[f(m)=\sum\limits_{i=0}^m(-1)^{m-i}\begin{bmatrix}m\\i \end{bmatrix}g(i) \]
於是我們就可以\(O(n^2)\)計算了。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define mod 1004535809
#define N 5005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int T;
ll n,m,c;
ll s1[N][N],g[N];
int main() {
s1[0][0]=1;
for(int i=1;i<=5000;i++)
for(int j=1;j<=5000;j++)
s1[i][j]=(s1[i-1][j-1]+(i-1)*s1[i-1][j])%mod;
T=Get();
while(T--) {
n=Get(),m=Get(),c=Get();
g[0]=1;
for(int i=1;i<=m;i++) g[i]=g[i-1]*c%mod;
ll ans=0;
int flag=m&1?1:-1;
for(int i=1;i<=m;i++,flag*=-1) {
ll now=1;
for(int j=1;j<=n;j++) now=now*(g[i]-j+1+mod)%mod;
(ans+=flag*s1[m][i]*now%mod+mod)%=mod;
}
cout<<ans<<"\n";
}
return 0;
}