Codechef:Billboards/BB(杨氏矩阵)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/83340204

传送门

题解:
显然的一点就是如果 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();
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83340204
bb