【Codechef】BB-Billboards
题解
传说中的……半标准杨表(行单调不增,列单调减)
如果N能整除M,我们把序列分成\(\frac{N}{M}\)段
然后里面要填K个1,显然我每一段必须填K个1,且可以构造出合法的序列,所以最少要填\(K\frac{N}{M}\)个1
我们列出一个K行\(\frac{N}{M}\)列的矩阵,\((i,j)\)表示第j段第i个1填的位置,显然列是单调降的,而每行需要单调不增
这是一个半标准的杨表
公式是\(\prod_{(i,j)} \frac{r + j - i}{hook(i,j)}\)
r是值域的大小
然后我们把要乘的数和要除的数列成一个矩阵,就会发现我们会约掉很多,只剩下两边总的大小不超过\(M*K\)的矩阵
那么\(N\)不整除\(M\)呢,我们根据\(N % M\)分类一下,设\(P = N % M\),\(P < M - K\),那么我们前面\(P\)位必须都填0
如果\(P > M - K\),那么我们新增一段,每段后\(M - P\)个位置必须填1
如果\(P = M - K\),那么只有唯一的一种方案
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 2005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,M,K;
const int MOD = 1000000007;
int inv[205];
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
void Solve(int r,int c,int m) {
int hr = r + c - 1,hl = r;
int tl = m,tr = m + c - 1;
int res = 1;
for(int i = hl ; i < tl ; ++i) {
for(int k = 0 ; k < r ; ++k) {
res = mul(res,inv[i - k]);
}
}
for(int i = hr + 1 ; i <= tr ; ++i) {
for(int k = 0 ; k < r ; ++k) {
res = mul(res,i - k);
}
}
out(res);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T;
read(T);
inv[1] = 1;
for(int i = 2 ; i <= 200 ; ++i) {
inv[i] = mul(inv[MOD % i],MOD - MOD / i);
}
while(T--) {
read(N);read(M);read(K);
int P = N % M;
if(P == M - K) puts("1");
else if(P < M - K) Solve(K,N / M,M - P);
else Solve(K - (M - P),N / M + 1,P);
}
return 0;
}