组合数问题

Posted akoasm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合数问题相关的知识,希望对你有一定的参考价值。

组合数问题

  • 题目描述

    见https://www.luogu.org/problemnew/show/P3746#sub

  • 数据范围

    (1 leq n leq 10^9,0 leq {r - 1} leq {k - 1} leq 50,2 leq p leq 2^{30} - 1)

  • 题解

    良心的30分可以通过组合递推得到。

    (p = 2)的时候直接(dp)方案数0或1即可。

    (k = 1)的时候显然答案就是(2^n)

    (k = 2)的时候答案是(2^{n - 1})

    直到80分你都可以使用逆元(O1)计算组合数。

    现在来分析一下题目中的组合数到底代表什么?

    其实就是从(n imes k)个物品中,选出(mod)k余(r)的方案数。

    考虑(dp)(dp[i][j])表示考虑前(i)个物品,选出来的物品数模(k)(j)的方案数。

    方程:(dp_{i + 1,j} = dp_{i,j} + dp_{i,j - 1})

    矩阵优化即可。

    复杂度(O(k^3 log_n))

    当然这已经足够通过本题。

    我们再来看看这个式子。

    可以表示成这个样子:(dp[2n][i + j] += dp[n][i] + dp[n][j])

    可以理解为从前(n)个物品中选(i)的方案数和从后(n)个物品中选(j)个的方案数是从整个

    $ 2 imes n(中选)i + j$个的方案数。

    直接倍增即可,复杂度(O(k^2 log_n))

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define int long long
    int ret[55], tmp[55], ttt[55], p;
    int n, r, k;
    void pow_mod(int n) {
      ret[0] = 1;
      if (k == 1) tmp[0] = 2;
      else tmp[0] = tmp[1] = 1;
      while (n) {
          if (n & 1ll) {
              for (int i = 0; i < k; ++i)
                  ttt[i] = 0;
              for (int i = 0; i < k; ++i)
                  for (int j = 0; j < k; ++j)
                      ttt[(i+j)%k] += (ret[i] * tmp[j]) % p;
              for (int i = 0; i < k; ++i)
                  ret[i] = ttt[i] % p;
          }
          for (int i = 0; i < k; ++i)
              ttt[i] = 0;
          for (int i = 0; i < k; ++i)
              for (int j = 0; j < k; ++j)
                  ttt[(i+j)%k] += (tmp[i] * tmp[j]) % p;
          for (int i = 0; i < k; ++i)
              tmp[i] = ttt[i] % p;
          n >>= 1ll;
      }
    }
    signed main() {
      scanf("%d %lld %d %d", &n, &p, &k, &r);
      pow_mod(n*k);
      printf("%lld", ret[r]);
    }

以上是关于组合数问题的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 代码片段

48个值得掌握的JavaScript代码片段(上)

片段组合在 Relay 中是如何工作的?

如何将片段中的 ListView 对象的数据传递给 Activity?

如何像浏览器一样在 Java 中组合 URL 片段?

使用 Apollo 客户端的片段组合:约定和样板