嘘~ 正在从服务器偷取页面 . . .

[AGC002F] Leftmost Ball 题解


[AGC002F] Leftmost Ball 题解

题目链接:[AGC002F] Leftmost Ball

题意

给你 \(n\) 种颜色的球,每种颜色的球有 \(k\) 个,把这 \(n\times k\) 个球排成一排,

把每一种颜色的最左边出现的球涂成白色(初始球不包含白色),求有多少种不同的颜色序列。

答案对 \(10^9+7\) 取模。

数据范围

\(1\leq n, k\leq 2000\)

可以看作 \(n\) 个白球和 \(n\) 种颜色的各 \(k-1\) 个球。特判 \(k=1\)

\(f(i,j)\) 为放了 \(i\) 白球和 \(j\) 其他颜色的球的合法方案数。

这里规定 \(j \le i\) ,称每个白球右侧到下一个白球前的位置为空位。考虑转移。

  • 在左侧第一个空位放一个白球,从 \(f(i-1,j)\) 处转移;

  • 在左侧第一个空位放至少一个其他颜色的球,然后放完该颜色的球,

    即从 \(f(i,j-1)\) 处转移。考虑转移系数。首先从剩下 \(n-j+1\) 种球里选一种放,

    然后在剩下的 \(nk-i-(j-1)(k-1)-1\) 个空位里放 \(k-2\) 个(第一个空位至少放一个)

那么转移方程就是 \[ f(i,j) = f(i-1,j) + f(i, j - 1) (n - j + 1) \binom{nk-i-(j-1)(k-1)-1}{k-2} \] 时间复杂度 \(\mathcal{O}(nk)\)

代码:

#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
typedef long long ll;
const int mod = 1e9 + 7;
template<typename T> void up(T &x, T y) { x < y ? x = y : 0; }
template<typename T> void down(T &x, T y) { x > y ? x = y : 0; }
template<typename T> void add(T &x, T y) { (x += y) >= mod ? x -= mod : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define N ((int)(2e3 + 15))
#define N2 ((int)(4e6 + 15))

ll fac[N2], ifac[N2], dp[N][N];
ll C(int n, int m)
{
    if(n < m || m < 0) return 0;
    return fac[n] * ifac[n - m] % mod * ifac[m] % mod;
}
ll qpow(ll a, int b)
{
    ll r = 1;
    for(a %= mod; b; b >>= 1, a = a * a % mod)
        if(b & 1) r = r * a % mod;
    return r;
}
void init(int n)
{
    fac[0] = 1;
    rep(i, 1, n) fac[i] = fac[i - 1] * i % mod;
    ifac[n] = qpow(fac[n], mod - 2);
    Rep(i, n - 1, 0) ifac[i] = ifac[i + 1] * (i + 1) % mod;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int n, k; cin >> n >> k; init(N2 - 5);
    if(k == 1) { return cout << "1\n", 0; }
    dp[0][0] = 1;
    rep(i, 1, n) rep(j, 0, i)
    {
        dp[i][j] = dp[i - 1][j];
        if(j)
        {
            const ll _1 = dp[i][j - 1] * (n - j + 1) % mod;
            const ll _2 = C(n - i + (n - j + 1) * (k - 1) - 1, k - 2);
            add(dp[i][j], _1 * _2 % mod);
        }
    }
    cout << dp[n][n] << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/pbm4dc6q

[2] https://www.luogu.com.cn/article/rpbu0cuz


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录