车的放置

题目:
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 ji
对于第 i i i行,有两种情况:放车或不放车。设第 i i i行有 x x x个格子,如果放车,那么前 i i i行放了 j − 1 j-1 j1个车,则第 i i i行可以放的格子数为 x − ( j − 1 ) x-(j-1) x(j1),根据乘法原理,放车的方案数为 f [ i − 1 ] [ j − 1 ] ∗ ( x − j + 1 ) f[i-1][j-1]*(x-j+1) f[i1][j1](xj+1);如果第 i i i行不放车,那么前 i − 1 i-1 i1行放了 j j j个车,方案数为 f [ i − 1 ] [ j − 1 ] f[i-1][j-1] f[i1][j1]

  • i ≤ b i\le b ib时, 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[i1][j]+f[i1][j1](aj+1)
  • b < i ≤ b + d b<i\le b+d b<ib+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[i1][j]+f[i1][j1](a+cj+1))

注意初始化

思路2:

  1. n ∗ n n*n nn的矩阵上放置 n n n个车,求放置方案:
    n ! n! n!
  2. 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!
  3. n ∗ m n*m nm的矩阵上放置 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 cd两个矩阵拼接而成。 f ( a , b , x ) f(a,b,x) f(a,b,x)表示在 a ∗ b a*b ab的矩阵中选 x x x个点的方案数。对于 c ∗ d c*d cd的矩阵,每选一个,则相当于 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+di,a,ki)

代码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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值