Link
Solution
可以先把 (k) 的限制去了,区间变为 ([lceilfrac{L}{k} ceil,lfloor frac{H}{k} floor]),记为 ([l,r]) 。那么只需要使 gcd 为一。
考虑一波反演,定义 (F(n)) 表示 gcd 是 (n) 的倍数的方案数,(f(n)) 表示 gcd 恰好是 (n) 的方案数,那么
[F(n)=Big( lfloor frac{r}{n}
floor - lfloor frac{l-1}{n}
floor Big )^N=sum_{n|d} f(d)
]
则有
[f(n)=sum_{d|n} mu(frac{d}{n})F(d)
]
答案就是
[f(1)=sum_{i=1}^{r} mu(i)Big( lfloor frac{r}{i}
floor - lfloor frac{l-1}{i}
floor Big )^N
]
套一个整数分块,然后用杜教筛求 (mu) 的区间和就可以了。注意整数分块的时候,(F) 的值和 (frac{r}{i}) 和 (frac{l-1}{i}) 都有关。
#include<stdio.h>
#include<unordered_map>
#include<cassert>
using namespace std;
#define ll long long
const int N=5e6+7;
const int Mod=1e9+7;
bool mk[N];
int p[N],cnt=0;
ll L,R,mu[N];
unordered_map<int,int> mp;
ll qpow(ll x,ll y){
ll ret=1;
while(y){
if(y&1) ret=ret*x%Mod;
x=x*x%Mod,y>>=1;
}
return ret;
}
void pre(){
mu[1]=1;
for(int i=2;i<N;i++){
if(!mk[i]){p[++cnt]=i,mu[i]=-1;}
for(int j=1;j<=cnt&&p[j]*i<N;j++){
mk[p[j]*i]=1;
if(i%p[j]==0) break;
mu[i*p[j]]=-mu[i];
}
mu[i]=(mu[i-1]+mu[i]+Mod)%Mod;
}
}
ll solve(ll x){
if(x<N) return mu[x];
if(mp[x]) return mp[x];
ll ret=1;
for(ll l=2,r=0;l<=x;l=r+1){
r=x/(x/l);
ret=(ret-(r-l+1)*solve(x/l)%Mod+Mod)%Mod;
}
return mp[x]=ret;
}
int main(){
ll n,k,H; pre();
scanf("%lld%lld%lld%lld",&n,&k,&L,&H);
L=(L-1)/k+1,R=H/k;
ll ans=0;
for(ll l=1,r=0;l<=R;l=r+1){
if(l>=L) r=R/(R/l);
else r=min(R/(R/l),(L-1)/((L-1)/l));
ans=(ans+qpow(R/l-(L-1)/l,n)*(solve(r)-solve(l-1)+Mod)%Mod)%Mod;
}
printf("%lld",ans);
}