题解
传说中的……半标准杨表(行单调不增,列单调减)
如果N能整除M,我们把序列分成(frac{N}{M})段
然后里面要填K个1,显然我每一段必须填K个1,且可以构造出合法的序列,所以最少要填(Kfrac{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('
')
#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;
}