Ubuntu中pycharm安裝
阿新 • • 發佈:2020-12-22
一、題目
二、解法
其實我們只需要關係一個數是不是 \(1\),至於 \(k\) 是拿給我們來算方案數的。
直接憑感覺容斥,欽定 \(i\) 行沒有 \(1\) ,\(j\) 列沒有 \(1\),\(t=(n-i)(n-j)\) 即是不被欽定格子的數量:
\[\sum_{i=0}^n\sum_{j=0}^n (-1)^{i+j}C(n,i)\times C(n,j)\times k^{t}\times (k-1)^{n^2-t} \]以 \(0\) 為起點的容斥係數多半是 \((-1)^i\) 之類的,類似的柿子是可以用二項式反演嚴格推導的:比如這位大佬的部落格,但用二項式反演推出來就不知道可不可以優化了。我正在嘗試能不能嚴格推出上面的式子。
時間複雜度 \(O(n^2)\) 其實已經足夠通過本題了,但是我們想能不能做到更好,優化的辦法是 去掉內層迴圈,由於這裡既有 \(-1\) 又有 \(C(n,j)\),所以我們可以嘗試使用 二項式定理 ,但是 \(k\) 的那些項要做相應的變形。
\[k^{(n-i)(n-j)}\times(k-1)^{(i+j)n-ij} \]\[k^{(n-i)(n-j)}\times(k-1)^{i(n-j)}\times(k-1)^{nj} \]\[(k^{n-i}\times(k-1)^i)^{n-j}\times((k-1)^n)^j \]這個變形也不是空穴來風,我們在配湊指數 \(n-j\) 和 \(j\) 以達到二項式定義中的指數定和,那麼最後的柿子變成:
所以時間複雜度優化成了 \(O(n\log n)\) ,程式碼也極好寫。
#include <cstdio> const int M = 305; const int MOD = 1e9+7; #define int long long int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,k,ans,inv[M],fac[M],f1[M],f2[M]; void init() { inv[0]=inv[1]=fac[0]=f1[0]=f2[0]=1; for(int i=2;i<=n;i++) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD; for(int i=2;i<=n;i++) inv[i]=inv[i-1]*inv[i]%MOD; for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD; for(int i=1;i<=n;i++) { f1[i]=f1[i-1]*(k-1)%MOD; f2[i]=f2[i-1]*k%MOD; } } int qkpow(int a,int b) { int r=1; while(b>0) { if(b&1) r=r*a%MOD; a=a*a%MOD; b>>=1; } return r; } int C(int n,int m) { if(n<m) return 0; return fac[n]*inv[m]%MOD*inv[n-m]%MOD; } signed main() { n=read();k=read(); init(); for(int i=0;i<=n;i++) { int t=(f1[i]*f2[n-i]-f1[n])%MOD; if(i%2==0) ans=(ans+C(n,i)*qkpow(t,n))%MOD; else ans=(ans-C(n,i)*qkpow(t,n))%MOD; } printf("%lld\n",(ans+MOD)%MOD); }