前置技能:
快速幂(雾)
杜教筛
狄利克雷卷积(莫比乌斯反演)
首先把答案表示出来:
这里先把
L
L
L和
R
R
R都除以
k
k
k,然后
g
c
d
=
k
gcd=k
gcd=k就转化成
g
c
d
=
1
gcd=1
gcd=1。
a
n
s
=
Σ
x
1
=
L
R
Σ
x
2
=
L
R
.
.
.
Σ
x
n
=
L
R
[
g
c
d
(
x
1
,
x
2
,
.
.
.
,
x
n
)
=
1
]
ans=\Large\Sigma\large_{x_1=L}^R\Large\Sigma\large_{x_2=L}^R...\Large\Sigma\large_{x_n=L}^R[gcd(x_1,x_2,...,x_n)=1]
ans=Σx1=LRΣx2=LR...Σxn=LR[gcd(x1,x2,...,xn)=1]
由
μ
∗
I
=
ε
\mu*I=ε
μ∗I=ε珂得
a
n
s
=
Σ
x
1
=
L
R
Σ
x
2
=
L
R
.
.
.
Σ
x
n
=
L
R
Σ
d
∣
g
c
d
(
x
1
,
x
2
,
.
.
.
,
x
n
)
μ
(
d
)
ans=\Large\Sigma\large_{x_1=L}^R\Large\Sigma\large_{x_2=L}^R...\Large\Sigma\large_{x_n=L}^R\Large\Sigma\large_{d|gcd(x_1,x_2,...,x_n)}\mu(d)
ans=Σx1=LRΣx2=LR...Σxn=LRΣd∣gcd(x1,x2,...,xn)μ(d)
=
Σ
x
1
=
L
R
Σ
x
2
=
L
R
.
.
.
Σ
x
n
=
L
R
Σ
d
∣
x
1
,
d
∣
x
2
,
.
.
.
,
d
∣
x
n
μ
(
d
)
=\Large\Sigma\large_{x_1=L}^R\Large\Sigma\large_{x_2=L}^R...\Large\Sigma\large_{x_n=L}^R\Large\Sigma\large_{d|x_1,d|x_2,...,d|x_n}\mu(d)
=Σx1=LRΣx2=LR...Σxn=LRΣd∣x1,d∣x2,...,d∣xnμ(d)
调换枚举顺序,先枚举
d
d
d,得到
a
n
s
=
Σ
d
=
1
R
μ
(
d
)
Σ
d
∣
x
1
Σ
d
∣
x
2
.
.
.
Σ
d
∣
x
n
1
ans=\Large\Sigma\large_{d=1}^R\mu(d)\Large\Sigma\large_{d|x_1}\Large\Sigma\large_{d|x_2}...\Large\Sigma\large_{d|x_n}1
ans=Σd=1Rμ(d)Σd∣x1Σd∣x2...Σd∣xn1
=
Σ
d
=
1
R
μ
(
d
)
(
⌊
R
d
⌋
−
⌊
L
−
1
d
⌋
)
n
=\Large\Sigma\large_{d=1}^R\mu(d)(\lfloor\frac{R}{d}\rfloor-\lfloor\frac{L-1}{d}\rfloor)^n
=Σd=1Rμ(d)(⌊dR⌋−⌊dL−1⌋)n
然后整除分块,求一下 μ \mu μ的前缀和(杜教筛),然后再来个快速幂即可qwq。
代码
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<map>
#define re register int
#define rl register ll
#define mod 1000000007
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
inline ll fpow(ll b,ll p,ll k) {
ll ans=1;
while(p) {
if(p&1) ans=ans*b%k;
b=b*b%k;
p>>=1;
}
return ans;
}
const int Size=2000005;
int tot,mu[Size],sum[Size],prime[Size];
bool vis[Size];
void getp(int maxn) {
mu[1]=1;
for(re i=2; i<=maxn; i++) {
if(!vis[i]) {
prime[++tot]=i;
mu[i]=-1;
}
for(re j=1; j<=tot; j++) {
int now=i*prime[j];
vis[now]=true;
if(now>maxn || i%prime[j]==0) {
break;
}
mu[now]=-mu[i];
}
}
for(re i=1; i<=maxn; i++) {
sum[i]=sum[i-1]+mu[i];
}
}
ll n,k,l,r;
//ll val[Size];
map<int,ll> val;
ll Sum(int x) {
if(x<=1000000) return sum[x];
int t=r/x,lst;
if(val[x]) return val[x];
ll ans=0;
for(re i=2; i<=x; i=lst+1) {
lst=x/(x/i);
ans=(ans+(ll)(lst-i+1)*Sum(x/i))%mod;
}
// vis[t]=true;
return val[x]=(1ll-ans+mod)%mod;
}
int main() {
// freopen("WA.txt","w",stdout);
getp(1000000);
memset(vis,0,sizeof(vis));
n=read();
k=read();
l=(read()-1)/k;
r=read()/k;
int lst,cnt=0;
ll ans=0;
for(re i=1; i<=r; i=lst+1) {
int tmpl=l/i,tmpr=r/i;
//注意特判l/i=0的情况,小心RE
if(!tmpl) {
lst=r/tmpr;
} else {
lst=min(l/tmpl,r/tmpr);
}
ans=((ans+fpow(tmpr-tmpl,n,mod)*(Sum(lst)-Sum(i-1)+mod)%mod)+mod)%mod;
// printf("%lld\n",ans);
}
printf("%lld",ans);
return 0;
}