题目:
https://ac.nowcoder.com/acm/problem/50592
有下面这样的一个网格棋盘,
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
1
0
5
+
3
mod\ 10^5+3
mod 105+3。
思路1:
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前
i
i
i行放了
j
j
j个车的方案数,显然
j
≤
i
j\le i
j≤i。
对于第
i
i
i行,有两种情况:放车或不放车。设第
i
i
i行有
x
x
x个格子,如果放车,那么前
i
i
i行放了
j
−
1
j-1
j−1个车,则第
i
i
i行可以放的格子数为
x
−
(
j
−
1
)
x-(j-1)
x−(j−1),根据乘法原理,放车的方案数为
f
[
i
−
1
]
[
j
−
1
]
∗
(
x
−
j
+
1
)
f[i-1][j-1]*(x-j+1)
f[i−1][j−1]∗(x−j+1);如果第
i
i
i行不放车,那么前
i
−
1
i-1
i−1行放了
j
j
j个车,方案数为
f
[
i
−
1
]
[
j
−
1
]
f[i-1][j-1]
f[i−1][j−1]。
- 当 i ≤ b i\le b i≤b时, f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − 1 ] ∗ ( a − j + 1 ) f[i][j]=f[i-1][j]+f[i-1][j-1]*(a-j+1) f[i][j]=f[i−1][j]+f[i−1][j−1]∗(a−j+1)
- 当 b < i ≤ b + d b<i\le b+d b<i≤b+d时, f [ i ] [ j ] = ( f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − 1 ] ∗ ( a + c − j + 1 ) ) f[i][j]=(f[i-1][j]+f[i-1][j-1]*(a+c-j+1)) f[i][j]=(f[i−1][j]+f[i−1][j−1]∗(a+c−j+1))
注意初始化
思路2:
-
n
∗
n
n*n
n∗n的矩阵上放置
n
n
n个车,求放置方案:
n ! n! n! - n*n的矩阵上放置k个车,求放置方案:
实际上是从 n n n行中选 k k k行, n n n列中选 k k k列配对,放置方案为 ( n k ) ( n k ) k ! {n\choose k}{n\choose k}k! (kn)(kn)k! -
n
∗
m
n*m
n∗m的矩阵上放置
k
k
k个车,求放置方案:
从 n n n行中选出 k k k行从 m m m列中选出 k k k列配对,放置方案为 ( n k ) ( m k ) k ! {n\choose k}{m\choose k}k! (kn)(km)k!
这道题可看作为
a
∗
(
b
+
d
)
a*(b+d)
a∗(b+d),
c
∗
d
c*d
c∗d两个矩阵拼接而成。
f
(
a
,
b
,
x
)
f(a,b,x)
f(a,b,x)表示在
a
∗
b
a*b
a∗b的矩阵中选
x
x
x个点的方案数。对于
c
∗
d
c*d
c∗d的矩阵,每选一个,则相当于
a
∗
(
b
+
d
)
a*(b+d)
a∗(b+d)的矩阵少一行可以选。
所以答案为
∑
i
=
0
k
f
(
c
,
d
,
i
)
f
(
b
+
d
−
i
,
a
,
k
−
i
)
\sum_{i=0}^{k}f(c,d,i)f(b+d-i,a,k-i)
∑i=0kf(c,d,i)f(b+d−i,a,k−i)。
代码1:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100003;
int a,b,c,d,n,m,f[2005][1005];
int main()
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&n);
m=b+d;
f[0][0]=1;//注意
for (int i=1; i<=b; i++)
f[i][0]=1;
for (int i=b+1; i<=m; i++)
f[i][0]=1;
for (int i=1; i<=b; i++)
for (int j=1; j<=i; j++)
f[i][j]=(f[i-1][j]+f[i-1][j-1]*(a-j+1))%maxn;
for (int i=b+1; i<=m; i++)
for (int j=1; j<=i; j++)
f[i][j]=(f[i-1][j]+f[i-1][j-1]*(a+c-j+1))%maxn;
printf("%d",f[m][n]);
return 0;
}