HDU 6363 bookshelf 【容斥+gcd+欧拉降幂】

题目链接

题意:
HDU 6363 bookshelf 【容斥+gcd+欧拉降幂】_第1张图片

HDU 6363 bookshelf 【容斥+gcd+欧拉降幂】_第2张图片

由于有 n=x1+x2+..+xk(xi>=0) n = x 1 + x 2 + . . + x k ( x i >= 0 ) ,假设 xi=gti x i = g ∗ t i ,那么 t1+...tk=n/g t 1 + . . . t k = n / g
所以系数一共有 C(n/g+k1,k1) C ( n / g + k − 1 , k − 1 ) 种情况,答案为 2f[g]1 2 f [ g ] − 1

g的倍数时会重复计算g的情况,因此要容斥。所以枚举n的因子时要从小到大枚举。

然后因为 2f[g] 2 f [ g ] 非常大,所以要欧拉降幂。

欧拉降幂公式:
这里写图片描述

需要注意的是只有在 B>=phi(C) B >= p h i ( C ) 的时候才需要 +phi(C) + p h i ( C ) ,相当于是把所有的数变成了0到 2phi(C) 2 p h i ( C )

#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int mod1 = 1e9 + 6;
const int maxn = 2000000 + 5;
const ll inf = 0x3f3f3f3f;

int T, cnt, n, k, p[maxn];
ll fac[maxn], inv[maxn], f[maxn], ff[maxn], dp[maxn];

ll qpow(ll x, ll n) {
    ll ans = 1;
    while (n) {
        if (n & 1)  ans = ans * x % mod;
        n >>= 1;
        x = x * x % mod;
    }
    return ans;
}

void init() {
    f[0] = 0, f[1] = 1; f[2] = 1;
    ff[0] = 0, ff[1] = 1, ff[2] = 1;
    for (int i = 3; i <= 1000001; i++) {
        f[i] = (f[i - 1] + f[i - 2]) % mod1;
        ff[i] = min(ff[i - 1] + ff[i - 2], 1ll * inf);
    }
    fac[0] = fac[1] = 1;
    inv[0] = inv[1] = 1;
    for (int i = 2; i <= 2000001; i++)  fac[i] = fac[i - 1] * i % mod;
    for (int i = 2; i <= 2000001; i++)  inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    for (int i = 2; i <= 2000001; i++)  inv[i] = inv[i] * inv[i - 1] % mod;
}

ll C(ll n, ll m) {
    ll ans = fac[n];
    ans = ans * inv[m] % mod;
    ans = ans * inv[n - m] % mod;
    return ans;
}

int main() {
#ifdef __APPLE__
    freopen("1.in", "r", stdin);
    // freopen("1.out", "w", stdout);
#endif
    init();
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &n, &k);
        cnt = 0;
        for (int i = 1; i * i <= n; i++) {
            if (n % i == 0) {
                p[++cnt] = i;
                if (i * i < n)
                    p[++cnt] = n / i;
            }
        }
        sort(p + 1, p + cnt + 1);
        for (int i = 1; i <= cnt; i++) {
            dp[i] = C(p[i] + k - 1, k - 1);
        }
        ll ans = 0;
        for (int i = 1; i <= cnt; i++) {
            ans = (ans + dp[i] * (qpow(2, f[n / p[i]] + (f[n / p[i]] >= mod1) * mod1) - 1 + mod)) % mod;
            for (int j = i + 1; j <= cnt; j++) {
                if (p[j] % p[i] == 0) {
                    dp[j] = (dp[j] - dp[i] + mod) % mod;
                }
            }
        }
        ans = ans * qpow(C(n + k - 1, k - 1), mod - 2) % mod;
        printf("%lld\n", ans);
    }
}

你可能感兴趣的:(ACM)