HDU 6363 容斥定理

题目链接


题意:
n n n个相同的小球放入 k k k个不同的箱子,箱子可以为空。假设对于一个方案, c n t [ i ] cnt[i] cnt[i]表示第 i i i个箱子中的小球数,则该方案的价值为: g c d ( 2 F i b [ c n t [ 1 ] ] − 1 , 2 F i b [ c n t [ 2 ] ] − 1 , 2 F i b [ c n t [ 3 ] ] − 1 , . . . , 2 F i b [ c n t [ k ] ] − 1 ) gcd(2^{Fib[cnt[1]]} - 1, 2^{Fib[cnt[2]]} - 1, 2^{Fib[cnt[3]]} - 1, ..., 2^{Fib[cnt[k]]} - 1) gcd(2Fib[cnt[1]]1,2Fib[cnt[2]]1,2Fib[cnt[3]]1,...,2Fib[cnt[k]]1),其中 F i b [ ] Fib[] Fib[]为斐波那契数列,问所有方案价值的期望是什么?


思路:
首先通过打表可以发现:

g c d ( 2 F i b [ c n t [ x ] ] − 1 , 2 F i b [ c n t [ y ] ] − 1 ) = 2 F i b [ g c d ( c n t [ x ] , c n t [ y ] ) ] − 1 gcd(2^{Fib[cnt[x]]} - 1, 2^{Fib[cnt[y]]} - 1) = 2^{Fib[gcd(cnt[x], cnt[y])]} - 1 gcd(2Fib[cnt[x]]1,2Fib[cnt[y]]1)=2Fib[gcd(cnt[x],cnt[y])]1

即一个方案的价值其实等价于求出 k k k个箱子中小球数量的 g c d gcd gcd,记为 g g g,则方案价值为:
2 F i b [ g ] − 1 2^{Fib[g]} - 1 2Fib[g]1

此时可以考虑容斥:
d p [ i ] dp[i] dp[i]表示 g = i g = i g=i的方案数
G [ i ] G[i] G[i]表示 g g g i i i的倍数的方案数。

显然 g g g n n n的约数
则求解 G [ i ] G[i] G[i],本质上是将 n / i n/i n/i i i i分到 k k k个箱子中,箱子可以为空,而此问题是一个经典的组合数学题,由隔板法得:
G [ i ] = C n / i + k − 1 k − 1 G[i] = C_{n/i + k - 1} ^ {k - 1} G[i]=Cn/i+k1k1

又由容斥定理,得:
d p [ i ] = G [ i ] − ∑ i ∣ j   a n d   j ∣ n d p [ j ] dp[i] = G[i] - \sum_{i|j \ and \ j|n}dp[j] dp[i]=G[i]ij and jndp[j]

则最终答案为:
A n s = ( ∑ i ∣ n d p [ i ] ∗ ( 2 F i b [ i ] − 1 ) ) / C n + k − 1 k − 1 Ans = (\sum_{i|n} dp[i] * (2^{Fib[i] } - 1) )/ C_{n + k - 1} ^ {k - 1} Ans=(indp[i](2Fib[i]1))/Cn+k1k1

而对于 2 F i b [ i ] − 1 2^{Fib[i] } - 1 2Fib[i]1的求解,可以考虑使用拓展欧拉定理进行降幂求解。
但通过打表可以发现一个更简单的递推式:
假设 g [ i ] = 2 F i b [ i ] − 1 g[i] = 2^{Fib[i] } - 1 g[i]=2Fib[i]1

则:
g [ i ] = g [ i − 1 ] ∗ g [ i − 2 ] + g [ i − 1 ] + g [ i − 2 ] g[i] = g[i-1]*g[i-2] + g[i-1] + g[i-2] g[i]=g[i1]g[i2]+g[i1]+g[i2]

此题得解。


代码:

#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;
const int A = 2e6 + 10;
ll g[A], Fac[A], Inv[A], dp[A], ans, n, k;

ll fast_mod(ll n, ll m){
    ll res = 1;
    while (m > 0) {
        if (m & 1) res = res * n % mod;
        n = n * n % mod;
        m >>= 1;
    }
    return res;
}

void Init(){
    g[0] = 0;
    g[1] = g[2] = 1;
    for (int i = 3; i < A; i++) {
        g[i] = (g[i-1] * g[i-2] % mod + g[i-1] + g[i-2]) % mod;
    }
    Fac[0] = Inv[0] = 1;
    for (int i = 1; i < A; i++) {
        Fac[i] = Fac[i-1] * i % mod;
    }
    Inv[A-1] = fast_mod(Fac[A-1], mod - 2);
    for (int i = A - 2; i >= 1; i--) {
        Inv[i] = Inv[i + 1] * (i + 1) % mod;
    }
}

ll Comb(ll n, ll m){
    return Fac[n] * Inv[m] % mod * Inv[n-m] % mod;
}

int main(){
    Init();
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%I64d%I64d", &n, &k);
        ans = 0;
        for (int i = n; i >= 1; i--) {
            if (n % i == 0){
                dp[i] = Comb(n/i + k - 1, k - 1);
                for (int j = 2 * i ; j <= n; j += i) {
                    if(n % j == 0) dp[i] = (dp[i] - dp[j]) % mod;
                }
                ans = (ans + dp[i] * g[i] % mod) % mod;
            }
        }
        ans = ans * fast_mod(Comb(n + k - 1, k - 1), mod - 2)% mod;
        if (ans < 0) ans += mod;
        printf("%I64d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(HDU 6363 容斥定理)