P3172 [CQOI2015]选数

首先,显然,可以把 \(L\) 便乘 \(\lfloor \frac{L}{K} \rfloor + [K \nmid L]\) 显然是因为如果 \(K \nmid L\) 那么 \(L\)\(\lfloor \frac{L}{K} \rfloor \cdot K\) 是不可能出现和其它数 \(\gcd\)\(K\) 的数的。也可以把 \(H\) 便乘 \(\lfloor \frac{H}{K} \rfloor\) 这个去掉的是上半部分,理由一致。那么相当于在求新的 \(L, H\) 之间互质的数的个数。

找出 \(L, H\) 之间 \(x\) 的倍数的个数 \(\frac{H}{K} - (\frac{L}{K} + [K \nmid L])\) (注意当后面大于前面直接conitnue)

然后令 \(f_{x}\) 为最大公因数是 \(x\)的倍数 的组合的个数。可知 \(f_{x} = \big( \frac{H}{K} - (\frac{L}{K} + [K \nmid L]) \big)^{N} - \big( \frac{H}{K} - (\frac{L}{K} + [K \nmid L]) \big)\)

那么逆序暴力加减计算就行了

最后别忘了,如果 \(\big(\lfloor \frac{L}{K} \rfloor + [K \nmid L]\big) = 1\) (也就是 \(L \le K \le H\)) 要给 \(ans + 1\)

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;
const ll MAXN = 1000010;
const ll MOD = 1e9 + 7;

ll N, K, L, H, F[MAXN];

ll kuaisu(ll, ll);

int main() {
    scanf("%lld%lld%lld%lld", &N, &K, &L, &H);
    L = L / K + (L % K > 0); H /= K;
    if (L > H) {
        puts("0");
        return 0;
    }
    for (ll d = 1; d <= H - L; d++) {
        ll l = L / d + (L % d > 0), r = H / d; if (l > r) continue;
        F[d] = (kuaisu(r - l + 1, N) - (r - l + 1) + MOD) % MOD;
        //printf("%lld ", F[d]);
    }
    //puts("");
    for (ll i = H-L; i >= 1; i--) {
        for (ll j = 2; j * i <= (H - L); j++) F[i] = (F[i] - F[j*i]) % MOD;
        //printf("%lld ", F[i]);
    }
    //puts("");
    if (L == 1) F[1] += 1;
    ll ans = F[1];
    while (ans < 0) {
        ans += MOD;
    }
    printf("%lld\n", ans % MOD);
    return 0;
}

ll kuaisu(ll n, ll tim) {
    ll tem = 1;
    while (tim) {
        if (tim & 1) {
            tem = (tem * n) % MOD;
        }
        tim >>= 1;
        n = (n * n) % MOD;
    }
    return tem;
}
posted @ 2020-09-13 21:23  Gensokyo_Alice  阅读(95)  评论(0)    收藏  举报