[SOJ407] 球动态规划组合数学

Posted suwakow

tags:

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

题意简述:有(n)个桶和(2n-1)个球,每个桶最多能装一个球,且第(i)个桶可以装前(2i-1)个球。问取(m)个桶和(m)个球,并将每个球放进一个桶里的方案数,(q)组询问。(1leq qleq 10^5, 1leq mleq nleq 10^7)


有一个显然的(O(nm))dp:设(f_{i, j})为前(i)个桶选了(j)个桶的方案数,考虑转移:

  • 若第(i)个桶不选,则(f_{i-1, j}Rightarrow f_{i, j})

  • 若第(i)个桶选,则前(2i-1)个球中有(j-1)个已经被选,剩余的可以自由选择,即(f_{i-1, j-1}cdot (2i-j)Rightarrow f_{i, j})

然后我们就可以打表啦!

观察发现(f_{n, m}=inom{n}{m}^2cdot m!),但是这个结论需要证明。

由这个式子不难想到,(n imes n)的棋盘中放(m)个无标号的互不攻击的车也是这个方案数,证明可以设(g_{i, j})(i imes i)的棋盘放(j)个车的方案数,考虑棋盘第(n)行、列(记为(S))的情况:

  • (S)中无车:显然答案为(g_{n-1, m})

  • (S)中有一个车:考虑剩下的((n-1) imes(n-1))的棋盘,显然方案数为(g_{n-1, m-1}),且剩余的能放车的位置有(2n-2m+1)个。

  • (S)中有两个车:考虑一个(g_{n-1, m-1})的情况,对于其中任意一种方案,我们均可以从(m-1)个车中选出一个((x, y)),将它拆成((x, n))((n, y))的两个车,显然这样的方案是一一对应的。

因此(g_{i, j}=g_{i-1, j}+(2i-j) g_{i-1, j-1}),发现与(f)的递推式完全一致。所以这个到底是怎么想到的啊

#include <cstdio>
#include <cctype>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
#define R register
#define ll long long
using namespace std;
const int N = 10010000, T = 110000, mod = 998244353;

int t, que[T][2], maxN;
ll fac[N], inv[N];

template <class T> inline void read(T &x) {
    x = 0;
    char ch = getchar(), w = 0;
    while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    x = w ? -x : x;
    return;
}

inline ll quickpow(ll base, ll pw) {
    ll ret = 1;
    while (pw) {
        if (pw & 1) ret = ret * base % mod;
        base = base * base % mod, pw >>= 1;
    }
    return ret;
}

int main() {
    read(t);
    for (R int i = 1; i <= t; ++i)
        read(que[i][0]), read(que[i][1]), maxN = max(maxN, que[i][0]);
    fac[0] = 1;
    for (R int i = 1; i <= maxN; ++i)
        fac[i] = fac[i - 1] * i % mod;
    inv[maxN] = quickpow(fac[maxN], mod - 2);
    for (R int i = maxN - 1; ~i; --i)
        inv[i] = inv[i + 1] * (i + 1) % mod;
    for (R int i = 1; i <= t; ++i) {
        int x = que[i][0], y = que[i][1];
        printf("%lld
", fac[x] * fac[x] % mod * inv[y] % mod * inv[x - y] % mod * inv[x - y] % mod);
    }
    return 0;
}

以上是关于[SOJ407] 球动态规划组合数学的主要内容,如果未能解决你的问题,请参考以下文章

Soj题目分类

动态规划数学期望/概率DP/期望DP详解

407,动态规划和滑动窗口解决最长重复子数组

算法题407:动态规划和滑动窗口解决最长重复子数组

动态规划专题6:打气球的最大分数

牛牛的猜球游戏(动态规划+前缀影响)