第十届集美大学程序设计竞赛正式赛 C题 方格染色 题解

前言

  • 记录一下,给自己长长记性,刚看到题目立马想出了一个 O ( T ∗ n k ) O(T*nk) O(Tnk)的暴力DP,想着构造个矩阵用快速幂优化为 O ( ∑ 1 T k ∗ l o g ( n ) ) O(\sum_1^T{k}*log(n)) O(1Tklog(n)),结果构造一个小时发现貌似不太行,想假了,悲(
  • 赛后做其他组合数的题突然想到这个题貌似也可以用组合数做,然后很快的就切了,以此题解铭记我坐了 3h 的牢
  • 本题解只提供思路讲解和核心代码,其余代码需要自己实现

正文

方格染色

小 M 正在处理染色问题!问题发生在一个由 2 × n 个 1 × 1 的小正方形方格组成的矩形纸条上,小 M 想要把矩形纸条的每个方格染成黑色或是白色。 但由于小 M 的视力不太好,若相邻两个方格都是黑色,小 M 会非常困惑。因此。他希望最后染色方 案中任意两个黑色方格均不相邻。同时,他还想知道在黑色方格恰好有 k 个的情况下,求出满足上述条 件的染色方案数对 998244353 取模的结果?

多测, T ≤ 1 0 5 , 1 ≤ n ≤ 1 0 5 , 0 ≤ k ≤ 1 0 5 T \le 10^5,1\le n \le 10^5,0 \le k \le 10^5 T1051n1050k105,保证 ∑ k ≤ 5 ∗ 1 0 5 \sum{k} \le 5 * 10^5 k5105

思路讲解

  • 用组合数做这个题,首先需要发现一个性质,如果我们把每一列看作是一个单独的整体
  • 定义:我们把相邻列有黑色块的列看作是一个块 \color{Orange}定义:我们把相邻列有黑色块的列看作是一个块 定义:我们把相邻列有黑色块的列看作是一个块
  • 那么这一个块内的不同摆放只有两种

在这里插入图片描述

  • 发现这个性质后,我们可以考虑枚举一共有多少个块,然后把这些块拿出来,现在还剩n-k列,我们需要做的就是把这些块插到这n-k列中,然后形成的方案数就是答案了

  • 那么怎么求方案数呢,这里先给出公式 ∑ d = 1 k C ( k − 1 , d − 1 ) ∗ C ( n − k + 1 , d ) ∗ 2 d \sum_{d=1}^k C(k-1,d-1)*C(n-k+1,d)*2^d d=1kC(k1,d1)C(nk+1,d)2d

  • 这个公式是怎么推出来的呢?

  • 首先我们枚举n列方格一共有多少的块,然后怎么求这些块形成的方案数呢,对于块数d,我们要做的就是把k列分成d个块,采用隔板法,即:现在有k个小球,你要在k个小球的之间放置d-1个隔板,使得分成d个非空集合,由于k个小球的缝的个数是k-1个(两边不可以插入),那么形成的方案应该是 C ( k − 1 , d − 1 ) C(k-1,d-1) C(k1,d1)

  • 由于每个块是不能相邻的(否则他们应该是一个块),现在需要把形成的d个块插入到原来的白色列的缝隙里,白色列的个数是n-k,那么缝数是n-k+1(两边可以插入),那么方案数就是 C ( n − k + 1 , d ) C(n-k+1,d) C(nk+1,d)

  • 对于每个块有两种摆放方式,那么d个块有 2 d 2^d 2d 种摆放方式

  • 之后我们只需要把不同的d的方案数累计起来即可,在不考虑取模的情况下时间复杂度为 O ( ∑ 1 T k ) O(\sum_1^T k) O(1Tk)

Code

void solve(int Case) {
    int n, k;
    cin >> n >> k;
    if (k == 0) {  // 只有什么都不放一种方案
        cout << "1\n";
        return;
    }
    if (n < k) {  // k太大,放不下
        cout << "0\n";
        return;
    }

    modint ans = 0;
    for (int d = 1; d <= k; d++) {
        ans += C(k - 1, d - 1) * C(n - k + 1, d) * modint(2).pow(d);
    }
    cout << ans << "\n";
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.Zero

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值