给出一个 \(n×m\) 大小的矩形,每一个位置能够填上$ [1,c]$中的任意一个数,要求填好后任意两行互不等价且任意两列互不等价,两行或两列等价当且仅当对应位置彻底相同,求方案数 。c++
\(n,m\le 5000\)spa
确实是一道神仙题。code
对这种行列都有限制的题咱们能够先只考虑一边。get
咱们先只考虑让行之间互不等价,一个\(n行m列\)且行互不等价的矩形的方案数为\((C^m)^{\underline{n}}\)。it
咱们设\(g(m)\)表示行互不等价的状况下,\(m\)列的矩形的方案数。\(g(m)=(C^m)^{\underline{n}}\)。class
咱们设\(f(m)\)表示行和列都分别互不等价的状况下,\(m\)列的矩形的方案数,也就是咱们要的答案。im
则:
\[ 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)\)计算了。di
代码:while
#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; }