1. 程式人生 > 其它 >題解[CF1228E Another Filling the Grid]

題解[CF1228E Another Filling the Grid]

題目

Luogu

CF

給定一個\(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)}\)

的意思是除去強制不合法的\(i\)​行\(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;
}

完結撒花❀