码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-10-15 21:30:43      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:组合数   答案   code   ons   main   register   names   转移   template   

题意简述:有\(n\)个桶和\(2n-1\)个球,每个桶最多能装一个球,且第\(i\)个桶可以装前\(2i-1\)个球。问取\(m\)个桶和\(m\)个球,并将每个球放进一个桶里的方案数,\(q\)组询问。\(1\leq q\leq 10^5, 1\leq m\leq n\leq 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}=\binom{n}{m}^2\cdot m!\),但是这个结论需要证明。

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

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

  • \(S\)中有一个车:考虑剩下的\((n-1)\times(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\n", fac[x] * fac[x] % mod * inv[y] % mod * inv[x - y] % mod * inv[x - y] % mod);
    }
    return 0;
}

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

标签:组合数   答案   code   ons   main   register   names   转移   template   

原文地址:https://www.cnblogs.com/suwakow/p/11680135.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!