题目地址:
https://www.acwing.com/problem/content/description/1311/
有下面这样的一个网格棋盘,
a
,
b
,
c
,
d
a,b,c,d
a,b,c,d表示了对应边长度,也就是对应格子数。
当
a
=
b
=
c
=
d
=
2
a=b=c=d=2
a=b=c=d=2时,对应下面这样一个棋盘:
要在这个棋盘上放
k
k
k个相互不攻击的车,也就是这
k
k
k个车没有两个车在同一行,也没有两个车在同一列,问有多少种方案。只需要输出答案
m
o
d
100003
\mod100003
mod100003后的结果。
输入格式:
共一行,五个非负整数
a
,
b
,
c
,
d
,
k
a,b,c,d,k
a,b,c,d,k。
输出格式:
包括一个正整数,为答案
m
o
d
100003
\mod100003
mod100003后的结果。
数据范围:
0
≤
a
,
b
,
c
,
d
,
k
≤
1000
0≤a,b,c,d,k≤1000
0≤a,b,c,d,k≤1000,保证至少有一种可行方案。
所有方案可以按照上面 b b b行放多少个来分类,如果上面 b b b行放 x x x个,下面 d d d行就只能放 k − x k-x k−x个。对于不同的 x x x方案互不交叉,从而可以用加法原理。我可以分步骤,考虑上面放 x x x个的方案,可以先选 x x x个不同行,方案数为 C ( b , x ) C(b,x) C(b,x),选定行的情况下,它们的列是排列数 A ( a , x ) A(a, x) A(a,x);考虑完上面接着考虑下面,同样先选行,则有 C ( d , k − x ) C(d, k-x) C(d,k−x)个方案,选定好行之后,只有 a + c − x a+c-x a+c−x个列可供选择,从而方案数为 A ( a + c − x , k − x ) A(a+c-x,k-x) A(a+c−x,k−x)。综上,方案数为 ∑ x = 0 b C ( b , x ) A ( a , x ) C ( d , k − x ) A ( a + c − x , k − x ) \sum_{x=0}^{b}C(b,x)A(a,x)C(d,k-x)A(a+c-x,k-x) x=0∑bC(b,x)A(a,x)C(d,k−x)A(a+c−x,k−x)组合数和排列数可以预处理出来。组合数可以利用 C ( n , k ) = C ( n − 1 , k − 1 ) + C ( n − 1 , k ) C(n,k)=C(n-1,k-1)+C(n-1,k) C(n,k)=C(n−1,k−1)+C(n−1,k)递推,排列数可以利用组合数求: A ( n , k ) = k ! C ( n , k ) A(n,k)=k!C(n,k) A(n,k)=k!C(n,k)。代码如下:
#include <iostream>
using namespace std;
using ll = long long;
const int N = 2010, MOD = 100003;
int a, b, c, d, k;
ll C[N][N], A[N][N];
int main() {
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
for (int i = 0; i <= max(max(b, d), a + c); i++)
for (int j = 0, fact = 1; j <= i; j++) {
if (!j) C[i][j] = 1;
else {
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
fact = fact * j % MOD;
}
A[i][j] = C[i][j] * fact % MOD;
}
int res = 0;
for (int x = 0; x <= b; x++)
res = (res + C[b][x] * A[a][x] % MOD * C[d][k - x] % MOD *
A[a + c - x][k - x] % MOD) % MOD;
printf("%d\n", res);
}
时间复杂度 O ( b ( max { b , d , a + c } ) 2 ) O(b(\max\{b,d,a+c\})^2) O(b(max{b,d,a+c})2),空间 O ( ( max { b , d , a + c } ) 2 ) O((\max\{b,d,a+c\})^2) O((max{b,d,a+c})2)。