HDU - 6397 Character Encoding 【容斥】 经典问题方程的解!!! 好题! 多校

版权声明:本文为博主原创文章,喜欢就点个赞吧 https://blog.csdn.net/Anxdada/article/details/81745090

传送门
题意:
求 x1 + x2 + …. + xm = k (0 <= xi < n), 这个方程的正整数解.

很明显, 如果xi>=0, 没有上界, 那么方程的解数为C(m-1, k+m-1), 可以用隔板法证明. 同理如果xi > 0, 那么解为C(m-1, k-1).

那么加了上界怎么判, 很明显我们就用总的去减, 但是会减重, 所以就是容斥, 容斥系数很容易推导为(-1)^c, c表示这m个变量中有c个违反了上界, 那么原方程变为 x1’ + x2’ + …. + xm’ = k - c*n, 其中xi’ = xi >= n ? xi-n : xi; 所以这个方程同理也能推出解为C(k - c*n + m -1, m -1); 然后再把容斥系数乘上就OK了.

注意要预处理出所有阶乘以及所有阶乘的逆元, 利用性质可以在O(n)的时间内预处理出来. 细节请看代码实现.

AC Code

const int maxn = 2e5+5;
ll inv[maxn], fac[maxn], infac[maxn];
void init() {
    fac[0] = 1;
    for(ll i = 1 ; i < maxn ; i ++) fac[i] = (fac[i-1]*i) % mod;  // 初始化n!数组.
    inv[1] = 1;
    for (int i = 2 ; i < maxn ; i ++) {
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    }
    infac[0] = 1;
    for (int i = 1 ; i < maxn ; i ++) {
        infac[i] = infac[i-1] * inv[i] % mod;
    }
}
ll Comb(ll m, ll n) {
    return fac[m] * infac[n] % mod * infac[m-n] % mod;
}
ll work(ll m, ll n) {
    if (m < n) return 0;
    return Comb(m, n);
}
void solve() {
    ll n, m, k;
    scanf("%lld%lld%lld", &n, &m, &k);
    ll ans = 0;
    for (ll i = 0 ; i <= m ; i ++) {
        ll tmp = Comb(m, i) * work(k-i*n+m-1, m-1) % mod;
        if (i&1) ans -= tmp;
        else ans += tmp;
        ans = (ans % mod + mod) % mod;
    }
    printf("%lld\n", ans);
}

记住这一类的好题!!!!

猜你喜欢

转载自blog.csdn.net/Anxdada/article/details/81745090