2019牛客暑期多校训练营(第七场)I——Chessboard(思维+组合数)
发布日期:2021-05-10 16:10:14 浏览次数:23 分类:精选文章

本文共 1859 字,大约阅读时间需要 6 分钟。

要解决这个问题,我们需要计算满足特定条件的排列方式的数量。具体来说,我们需要确保在任意选择的k×k正方形区域内的玻璃球总数相同,并且总和不超过给定的上限。以下是详细的解决思路和代码实现:

问题分析

  • 问题理解:我们需要在棋盘上放置玻璃球,使得每个k×k正方形区域的玻璃球总数相同。每个方格至少放置m个球,总和不超过n。
  • 约束条件:无论选择哪个k×k的区域,总和都必须相同。这意味着棋盘上的每个方格可能必须具有相同的值,或者存在某种周期性排列,使得每个k×k区域的总和相同。
  • 组合数学:根据官方题解,答案涉及组合数和阶乘的应用。我们需要计算每个可能的k值,满足条件的排列方式的数量,并将它们相加。
  • 解决思路

  • 预计算阶乘和逆阶乘:为了高效计算组合数,我们需要预先计算阶乘和逆阶乘,并使用模运算来避免数值溢出。
  • 动态规划:对于每个k值,计算满足条件的排列方式的数量。使用组合数来计算可能的排列方式,并对结果取模。
  • 组合数计算:使用预计算的阶乘和逆阶乘来快速计算组合数,确保计算的高效性和准确性。
  • 代码实现

    MOD = 998244353
    def main():
    import sys
    input = sys.stdin.read
    data = input().split()
    T = int(data[0])
    idx = 1
    max_n = 2000 * 2 # 根据题目约束,n和m不超过2000
    f = [1] * (max_n + 1)
    finv = [1] * (max_n + 1)
    for i in range(2, max_n + 1):
    f[i] = f[i-1] * i % MOD
    finv[i] = finv[i-1] * pow(i, MOD-2, MOD) % MOD
    def comb(n, k):
    if k < 0 or k > n:
    return 0
    return f[n] * finv[k] % MOD * finv[n - k] % MOD
    results = []
    for _ in range(T):
    n = int(data[idx])
    m = int(data[idx+1])
    idx +=2
    ans = 0
    for k in range(1, n+1):
    max_t = n - k * m
    if max_t < 0:
    continue
    current = 0
    for t in range(0, max_t +1):
    c = comb(t + 2*k -1, 2*k -1)
    current = (current + c) % MOD
    if t >= k:
    c_sub = comb(t + k -1, 2*k -1)
    current = (current - c_sub) % MOD
    ans = (ans + current) % MOD
    results.append(ans % MOD)
    for res in results:
    print(res)
    if __name__ == "__main__":
    main()

    代码解释

  • 输入处理:读取输入数据,解析测试用例的数量和每个测试用例的参数。
  • 预计算阶乘和逆阶乘:使用预计算的方法计算阶乘和逆阶乘,以便快速计算组合数。
  • 组合数函数:定义组合数函数comb(n, k),使用预计算的阶乘和逆阶乘来高效计算。
  • 动态规划计算:对于每个k值,计算满足条件的排列方式的数量。使用组合数累加和减去重叠部分,确保正确计数。
  • 输出结果:对每个测试用例的结果进行模运算后输出。
  • 通过上述方法,我们能够高效地解决问题并计算满足条件的排列方式的数量。

    上一篇:银联高校极客挑战赛 复赛(A,B,思维+数学)
    下一篇:杭电2019多校第五场 HDU——6635 Nonsense Time(思维动态lis)

    发表评论

    最新留言

    路过,博主的博客真漂亮。。
    [***.116.15.85]2025年04月28日 20时05分04秒