題解[CF1228E Another Filling the Grid]
阿新 • • 發佈:2021-10-02
題目
給定一個\(n\cdot n\)的矩陣,用\(1\)到\(k\)填充,要求每行每列至少有\(1\)個\(1\),求方案數。
Sol
感覺和一道三色填充的題有一些共同之處。CF997C
但是這道題可以\(O(n^3)\)(應該吧)。
所以仔細轉化一下題意就可以有容斥的思路。
列舉\(i,j\),表示欽定\(i\)行\(j\)列不合法,剩下的隨便放。
如何保證不合法呢?強制只能選取\(2\)到\(k\)的整數就行了。
\[ans=\sum\limits_{i=0}^n\sum\limits_{j=0}^n(-1)^{i+j}\binom{n}{i}\binom{n}{j}k^{(n-i)(n-j)}(k-1)^{n\cdot n-(n-i)(n-j)} \]\(k^{(n-i)(n-j)}\)
複雜度\(O(n^2log\ n)\)。
可以預處理快速冪省掉一個\(log\),但沒必要。
Code
#include<bits/stdc++.h> #define N (255) #define ll long long using namespace std; const ll P=1000000007; ll n,K,ans,fc[N],inv[N]; inline ll read(){ ll w=0; char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9'){ w=(w<<3)+(w<<1)+(ch^48); ch=getchar(); } return w; } inline ll ksm(ll a,ll b){ ll res=1; while(b){ if(b&1) res=res*a%P; a=a*a%P; b>>=1; } return res; } int main(){ n=read(),K=read(); fc[0]=inv[0]=1; for(ll i=1;i<=n;i++) fc[i]=fc[i-1]*i%P; inv[n]=ksm(fc[n],P-2); for(ll i=n-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%P; for(ll i=0;i<=n;i++){ for(ll j=0;j<=n;j++){ ll res1=fc[n]*inv[i]%P*inv[n-i]%P*fc[n]%P*inv[j]%P*inv[n-j]%P; ll res2=ksm(K,(n-i)*(n-j))*ksm(K-1,n*i+n*j-i*j)%P; ll res=res1*res2%P; if((i+j)&1) ans=(ans-res+P)%P; else ans=(ans+res)%P; } } printf("%lld\n",ans); return 0; }