看到 $n=250$ 顯然考慮 $n^3$ 的 $dp$
設 $f[i][j]$ 表示填完前 $i$ 行,目前有 $j$ 列的最小值是 $1$ 的合法方案數
那么對於 $f[i][j]$ ,枚舉 $f[i-1][k]$ ,有 $f[i][j]=\sum_{k=0}^{j}\binom{n-k}{j-k}f[i-1][k](m-1)^{n-j}m^k$
這里 $m$ 就是題目的 $k$
$\binom{n-k}{j-k}$ 是因為多出來的 $j-k$ 列 $1$ 可以任選
$(m-1)^{n-j}$ 是保證沒有 $1$ 的列不能填 $1$ ,只有 $m-1$ 種填的數
$m^k$ 是那些原本有保證為 $1$ 的列怎么填都行
當然剩下的那 $j-k$ 個位置顯然都是 $1$ ,方案數只有 $1$
然后這樣就可以做到 $n^3 \log n$ 然后發現竟然 $T$ 了,所以預處理一下 $k \in [0,n],m^k$ 和 $k \in [0,n],(m-1)^k$ 即可

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int mo=1e9+7,N=507; inline int fk(int x) { return x>=mo ? x-mo : x; } int n,m; int C[N][N],f[N][N]; int mi[N],mi_1[N]; int main() { n=read(),m=read(); for(int i=0;i<=n;i++) { C[i][0]=1; for(int j=1;j<=i;j++) C[i][j]=fk(C[i-1][j]+C[i-1][j-1]); } mi[0]=mi_1[0]=1; for(int i=1;i<=n;i++) { mi[i]=1ll*mi[i-1]*m%mo; mi_1[i]=1ll*mi_1[i-1]*(m-1)%mo; } for(int j=1;j<=n;j++) f[1][j]=1ll*C[n][j]*mi_1[n-j]%mo; for(int i=2;i<=n;i++) for(int j=0;j<=n;j++) { for(int k=0;k<=j;k++) { int x=1ll*f[i-1][k]*C[n-k][j-k]%mo; int y=1ll*mi_1[n-j]*mi[k]%mo; f[i][j]=fk(f[i][j]+1ll*x*y%mo); if(j==k) f[i][j]=fk(f[i][j]-1ll*mi_1[n]*f[i-1][k]%mo+mo); } } printf("%d\n",f[n][n]); return 0; }
但是有些神仙看完數據說:" $n$ 太小了,可以出到 $10^5$ 級別"
所以考慮一下神仙的做法
看到有限制的方案數,考慮容斥!
總方案 - (一行不合法+一列不合法) + (兩行不合法+兩列不合法+一行一列不合法) - ......
那么寫成式子就是長這個樣子:
$\sum_{i=0}^{n}\sum_{j=0}^{n}(-1)^{i+j} \binom{n}{i}\binom{n}{j}m^{n^2-n(i+j)+ij}(m-1)^{n(i+j)-ij}$
上面 $m^{n^2-n(i+j)+ij}$ 就是沒限制的位置順便填,$(m-1)^{n(i+j)-ij}$ 就是強制 $i$ 行 $j$ 列的格子不能填 $1$
然后同樣預處理一下 $m$ 和 $m-1$ 的冪次就可以做到 $n^2$
對着這個式子繼續搞:
$\sum_{i=0}^{n}\sum_{j=0}^{n}(-1)^{i+j} \binom{n}{i}\binom{n}{j}m^{n^2-n(i+j)+ij}(m-1)^{n(i+j)-ij}$
$\sum_{i=0}^{n}(-1)^i\binom{n}{i}\sum_{j=0}^{n}(-1)^j\binom{n}{j}m^{(n-i)(n-j)}(m-1)^{(n-i)j}(m-1)^{ni}$
$\because \sum_{j=0}^{n}(-1)^j\binom{n}{j}m^{(n-i)(n-j)}(m-1)^{(n-i)j}=(m^{n-i}-(m-1)^{n-i})^n$
$\therefore \sum_{i=0}^{n}(-1)^i\binom{n}{i}(m-1)^{ni}(m^{n-i}-(m-1)^{n-i})^n$
$\sum_{i=0}^{n}(-1)^i\binom{n}{i}(m^{n-i}(m-1)^i-(m-1)^n)^n$
然后就可以 $n \log n$ 解決了
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=507,mo=1e9+7; inline int fk(int x) { return x>=mo ? x-mo : x; } int n,m,Ans; int C[N][N],mi[N],m_1i[N]; inline int ksm(int x,int y) { int res=1; while(y) { if(y&1) res=1ll*res*x%mo; x=1ll*x*x%mo; y>>=1; } return res; } int main() { n=read(),m=read(); for(int i=0;i<=n;i++) { C[i][0]=1; for(int j=1;j<=i;j++) C[i][j]=fk(C[i-1][j]+C[i-1][j-1]); } mi[0]=m_1i[0]=1; for(int i=1;i<=n;i++) { mi[i]=1ll*mi[i-1]*m%mo; m_1i[i]=1ll*m_1i[i-1]*(m-1)%mo; } for(int i=0;i<=n;i++) { int t=1ll*C[n][i]*ksm( fk(1ll*mi[n-i]*m_1i[i]%mo - m_1i[n] +mo) , n )%mo; i&1 ? Ans=fk(Ans-t+mo) : Ans=fk(Ans+t); } printf("%d\n",Ans); return 0; }