1. 程式人生 > >Codechef:Billboards/BB(楊氏矩陣)

Codechef:Billboards/BB(楊氏矩陣)

傳送門

題解:
顯然的一點就是如果 n   m o d   m = 0

n \bmod m = 0 那麼相當與是每隔 m m 個塊裡面就要放 k k 個,而且每個塊這 k
k
箇中每一個的位置都單調不降。

此時相當於就是統計一下半標準楊氏矩陣(列單調降,行非嚴格單調降)的個數,根據鉤子定理,可以知道,當矩陣中最大元素為 r r 時,楊氏矩陣方案數為:

( i , j ) r + j i h o o k ( i , j ) \prod_{(i,j)}\frac{r+j-i}{hook(i,j)}

h o o k ( i , j ) hook(i,j) ( i , j ) (i,j) 位置的鉤子長度。

然後會發現乘法和除法有很多位置是相同的,去掉這些相同的之後,就變成了只需要求 m m 列的乘積,這個直接暴力是 O ( m 2 ) O(m^2) 的,用一點技巧就可以優化到 O ( m log ( 1 0 9 + 7 ) ) O(m \log (10^9+7))

n   m o d   m ̸ = 0 n \bmod m \not = 0 稍微討論一下就可以轉化為 n   m o d   m = 0 n \bmod m = 0 的情況了。

#include <bits/stdc++.h>
using namespace std;

const int mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
inline int cinv(int x) {return power(x,mod-2);}

inline int calc(int i,int k) {
	int ans=1;
	for(int j=0;j<k;j++) ans=mul(ans,i-j);
	return ans;
}
inline int calc(int l1,int r1,int l2,int r2,int k) {
	int ans=1;
	if(l1>r2) {
		for(int i=l1;i<=r1;i++) ans=mul(ans,calc(i,k));
		for(int i=l2;i<=r2;i++) ans=mul(ans,cinv(calc(i,k)));
	} else {
		for(int i=r2+1;i<=r1;i++) ans=mul(ans,calc(i,k));
		for(int i=l2;i<=l1-1;i++) ans=mul(ans,cinv(calc(i,k)));
	} return ans;
}
inline void solve() {
	int n,m,k; 
	cin>>n>>m>>k;
	if(!(n%m)) n/=m;
	else {
		int res=n%m; n=n/m+1;
		if(m-res<=k) {
			k=k-(m-res);
			m=res;
		} else {
			m=m-res; --n;
		}
	}
	cout<<calc(m,m+n-1,k,k+n-1,k)<<'\n';	
}
int main() {
	int T; cin>>T;
	while(T--) solve();
}