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;
}

浙公网安备 33010602011771号