把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

P3172 [CQOI2015] 选数 分析

题目概述

给你区间 \([L,R]\),从中选出 \(N\) 个数的 \(\gcd\) 恰好为 \(k\) 的数量。

分析

一开始直接套路:设 \(f(d)\) 表示倍数,\(F(d)\) 恰好。

然后搞完之后发现后面很复杂。

你需要进行一些转化,设 \(f(d)\) 表示倍数的方案(但是要求不全相同),然后都不用乘上莫比乌斯函数了,直接容斥就行了。

要求不完全相同那直接减去 \((r-l+1)\) 即可。

代码

时间复杂度 \(\mathcal{O}((R-L+1)\log (R-L+1))\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define int long long
#define N 100005
using namespace std;
const int mod = 1e9 + 7;
int qpow(int a,int b) {
    int res = 1;
    while(b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
int n,k,L,R,f[N];
signed main(){
    cin >> n >> k >> L >> R;
    L = (L + k - 1) / k,R /= k,k = 1;
    if (L > R) return puts("0"),0;
    for (int i = 1;i <= R - L;i ++) {
        int l = L,r = R;
        l = (l + i - 1) / i,r /= i;
        if (l > r) continue;
        f[i] = (qpow(r - l + 1,n) - (r - l + 1) + mod) % mod;
    }
    for (int i = R - L;i;i --)
        for (int j = (i << 1);j <= R - L;j += i)
            f[i] = (f[i] - f[j] + mod) % mod;
    cout << (f[1] + (L == 1)) % mod;
    return 0;
}
posted @ 2025-10-21 11:23  high_skyy  阅读(3)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end