题目描述

我们知道,从区间 [L,H](L 和 H 为整数)中选取 N 个整数,总共有 (H-L+1)^N
种方案。小 z 很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的 N 个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小 z 会告诉你一个整数 K,你需要回答他最大公约数刚好为 KK 的选取方案有多少个。由于方案数较大,你只需要输出其除以 1000000007 的余数即可。

输入格式

输入一行,包含四个空格分开的正整数,依次为 N,K,L,H。

输出格式

输出一个整数,为所求方案数。

输入输出样例

输入 #1

2 2 2 4

输出 #1

3

分析

有两种做法,第一种是反演后杜教筛,第二种是容斥。
首先化简式子:
<munderover> a 1 = L H </munderover> <munderover> a 2 = L H </munderover> . . . <munderover> a n = L H </munderover> [ gcd ( a 1 , a 2 , . . . . , a n ) = = k ] = <munderover> a 1 = <mstyle mathsize="0&#46;5em"> L K </mstyle> <mstyle mathsize="0&#46;5em"> H K </mstyle> </munderover> <munderover> a 2 = <mstyle mathsize="0&#46;5em"> L K </mstyle> <mstyle mathsize="0&#46;5em"> H K </mstyle> </munderover> . . . <munderover> a n = <mstyle mathsize="0&#46;5em"> L K </mstyle> <mstyle mathsize="0&#46;5em"> H K </mstyle> </munderover> [ gcd ( a 1 , a 2 , . . . . , a n ) = = 1 ] \sum\limits_{a_1=L}^{H}\sum\limits_{a_2=L}^{H}...\sum\limits_{a_n=L}^{H}[\gcd(a_1,a_2,....,a_n)==k]\\=\sum\limits_{a_1={\tiny\left\lceil\frac{L}{K}\right\rceil}}^{\tiny\left\lfloor\frac{H}{K}\right\rfloor}\sum\limits_{a_2={\tiny\left\lceil\frac{L}{K}\right\rceil}}^{\tiny\left\lfloor\frac{H}{K}\right\rfloor}...\sum\limits_{a_n={\tiny\left\lceil\frac{L}{K}\right\rceil}}^{\tiny\left\lfloor\frac{H}{K}\right\rfloor}[\gcd(a_1,a_2,....,a_n)==1] a1=LHa2=LH...an=LH[gcd(a1,a2,....,an)==k]=a1=KLKHa2=KLKH...an=KLKH[gcd(a1,a2,....,an)==1]

第一种做法

然后我们不妨令 L = L K L=\left\lceil\frac{L}{K}\right\rceil L=KL H = H K H=\left\lfloor\frac{H}{K}\right\rfloor H=KH
然后 = <munderover> x = 1 H </munderover> μ ( x ) ( H x L 1 x ) N 原式=\sum\limits_{x=1}^{H}\mu(x)(\left\lfloor\frac{H}{x}\right\rfloor-\left\lfloor\frac{L-1}{x}\right\rfloor)^{N} =x=1Hμ(x)(xHxL1)N
然后 分块 + 杜教筛 就完事了。
复杂度 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)

代码如下
#include <bits/stdc++.h>
#define LL long long
#define N 3000007
#define inf 2147483647
using namespace std;
const int mod = 1e9 + 7;
LL z = 1, t, ans;
int p[N], x[N], cnt, s[N], L, H, mu[N], f[N], maxn = N - 7;
unordered_map<int, int> ma;
int ksm(int a, int b, int p){
	int s = 1;
	while(b){
		if(b & 1) s = z * s * a % mod;
		a = z * a * a % mod;
		b >>= 1;
	}
	return s;
}
int getsum(int x){
	if(x <= maxn) return s[x];
	if(ma[x]) return ma[x];
	int l, r, sum = 0;
	for(l = 2; l <= x; l = r + 1){
		r = x / (x / l);
		sum = (sum + z * (r - l + 1) * getsum(x / l) % mod) % mod;
	}
	ma[x] = (1 - sum) % mod;
	return ma[x];
}
int main(){
	int i, j, n, m, l, k, r;
	mu[1] = 1;
	for(i = 2; i <= maxn; i++){
		if(!x[i]) x[i] = p[++cnt] = i, mu[i] = -1;
		for(j = 1; j <= cnt; j++){
			t = z * i * p[j];
			if(t > maxn) break;
			x[t] = p[j];
			if(i % p[j] == 0) break;
			mu[t] = -mu[i];
		}
	}
	for(i = 1; i <= maxn; i++) s[i] = s[i - 1] + mu[i];
	scanf("%d%d%d%d", &n, &k, &L, &H);
	L = (L - 1) / k + 1; L--;
	H = H / k;
	for(l = 1; l <= H; l = r + 1){
		r = min(H / (H / l), L / l? L / (L / l): inf);
		ans = (ans + z * ksm(H / l - L / l, n, mod) * (getsum(r) - getsum(l - 1)) % mod) % mod;
		//if(l >= L) printf("%d %d %d %d %d %d====\n", l, r, getsum(r), getsum(l - 1), ksm(H / l - L / l, n, mod), (getsum(r) - getsum(l - 1)) % mod);
	}
	printf("%lld", (ans % mod + mod) % mod);
	return 0;
}

第二种做法

f ( k ) f(k) f(k) 表示最大公约数恰好为 k k k不全相同的方案数, g ( k ) g(k) g(k) 表示 最大公约数为 k k k不全相同的方案数。
对于这个不全相同,我要解释一下。因为原题中 H L 1 0 5 H-L\leq 10^5 HL105,所以对于 x > H L x>H-L x>HL [ H , L ] [H,L] [H,L] 中一定不存在两个及以上不同的数,使得他们的 gcd \gcd gcd x x x,如果我们规定这些数不全相同,我们就不用考虑 x > H L x>H-L x>HL 的数了,把范围缩小到了 1 0 5 10^5 105
假设 t t t k k k [ L , H ] [L,H] [L,H] 之间的倍数个数,显然 t = ( H x L 1 x ) t=(\left\lfloor\frac{H}{x}\right\rfloor-\left\lfloor\frac{L-1}{x}\right\rfloor) t=(xHxL1)
那么 g ( k ) = t N t g(k) = t^N - t g(k)=tNt
那么最大公约数恰为 k k k 的方案数等于最大公约数是 k k k 倍数的方案数减去最大公约数恰为 2 k , 3 k , . . . m k 2k,3k,...mk 2k,3k,...mk 的方案数,即
f ( k ) = g ( k ) f ( 2 k ) f ( 3 k ) . . . f ( m k ) f(k) = g(k) - f(2k)-f(3k)-...-f(mk) f(k)=g(k)f(2k)f(3k)...f(mk)
最后要注意,若 L = 1 L=1 L=1,所有数都可以取 1 1 1
复杂度 O ( n ln n ) O(n\ln n) O(nlnn)

代码如下
#include <bits/stdc++.h>
#define LL long long
#define N 100005
using namespace std;
const int mod = 1e9 + 7;
LL z = 1;
int f[N];
int ksm(int a, int b, int p){
	int s = 1;
	while(b){
		if(b & 1) s = z * s * a % p;
		a = z * a * a % p;
		b >>= 1;
	}
	return s;
}
int main(){
	int i, j, n, m, x, k, L, H;
	scanf("%d%d%d%d", &n, &k, &L, &H);
	L = (L - 1) / k + 1;
	H = H / k;
	for(i = 1; i <= H - L; i++){
		x = (H / i - (L - 1) / i);
		x %= mod;
		f[i] = ((ksm(x, n, mod) - x) % mod + mod) % mod;
	}
	for(i = H - L; i >= 1; i--){
		for(j = 2; j <= (H - L) / i; j++){
			f[i] = (f[i] - f[i * j] + mod) % mod;
		}
	}
	if(L == 1) f[1] = (f[1] + 1) % mod;
	printf("%d", f[1]);
	return 0;
}