题目:
https://ac.nowcoder.com/acm/problem/21546
牛牛有一个区间
[
L
,
R
]
[L,R]
[L,R],需要选择
N
N
N个数,这
N
N
N个数都在这个区间范围内,那么我们知道一共有
(
R
−
L
+
1
)
N
(R - L + 1) ^ N
(R−L+1)N种选法,假如我们想要这
N
N
N个数的最大公约数恰好是
K
K
K.请问一共有多少种选法,输出答案对
1
0
9
+
7
10^9+7
109+7取模.
N
,
K
,
L
,
R
(
1
≤
N
,
K
,
L
≤
1
0
9
,
L
≤
R
≤
1
0
9
)
0
≤
R
−
L
≤
1
0
5
N,K,L,R (1\le N, K, L\le10^9, L\le R\le10^9)\quad0\le R-L\le10^5
N,K,L,R(1≤N,K,L≤109,L≤R≤109)0≤R−L≤105
思路:
∑
i
1
=
l
r
.
.
.
∑
i
n
=
l
r
[
(
i
1
.
.
.
.
i
n
)
=
k
]
=
∑
i
1
=
⌈
l
k
⌉
⌊
r
k
⌋
.
.
.
∑
i
n
=
⌈
l
k
⌉
⌊
r
k
⌋
[
(
i
1
.
.
.
.
i
n
)
=
1
]
令
l
=
⌈
l
k
⌉
,
r
=
⌊
r
k
⌋
=
∑
i
1
=
l
r
.
.
.
∑
i
n
=
l
r
[
(
i
1
.
.
.
.
i
n
)
=
1
]
=
∑
i
1
=
l
r
.
.
.
∑
i
n
=
l
r
∑
d
∣
(
i
1
.
.
.
i
2
)
μ
(
d
)
=
∑
d
=
1
r
∑
i
1
=
l
r
.
.
.
∑
i
n
=
l
r
[
d
∣
(
i
1
.
.
.
i
n
)
]
μ
(
d
)
=
∑
d
=
1
r
μ
(
d
)
∑
i
1
=
l
r
[
d
∣
i
1
]
.
.
.
∑
i
n
=
l
r
[
d
∣
i
n
]
只
要
另
i
j
是
d
的
倍
数
就
满
足
d
∣
(
i
1
.
.
.
i
n
)
=
∑
d
=
1
r
μ
(
d
)
(
⌊
r
d
⌋
−
⌊
l
−
1
d
⌋
)
n
分
块
+
杜
教
筛
\begin{aligned} &\sum_{i_1=l}^{r}...\sum_{i_n=l}^{r}[(i_1....i_n)=k]\\ =&\sum_{i_1=\lceil \frac{l}{k} \rceil}^{\lfloor \frac{r}{k} \rfloor}...\sum_{i_n=\lceil \frac{l}{k} \rceil}^{\lfloor \frac{r}{k} \rfloor}[(i_1....i_n)=1]\quad 令l=\lceil \frac{l}{k} \rceil,r=\lfloor \frac{r}{k} \rfloor\\ =&\sum_{i_1=l}^{r}...\sum_{i_n=l}^{r}[(i_1....i_n)=1]\\ =&\sum_{i_1=l}^{r}...\sum_{i_n=l}^{r}\sum_{d|(i_1...i_2)}\mu(d)\\ =&\sum_{d=1}^{r}\sum_{i_1=l}^{r}...\sum_{i_n=l}^{r}[d|(i_1...i_n)]\mu(d)\\ =&\sum_{d=1}^{r}\mu(d)\sum_{i_1=l}^{r}[d|i_1]...\sum_{i_n=l}^{r}[d|i_n]\quad 只要另i_j是d的倍数就满足d|(i_1...i_n)\\ =&\sum_{d=1}^{r}\mu(d)(\lfloor \frac{r}{d} \rfloor-\lfloor \frac{l-1}{d} \rfloor)^n\quad分块+杜教筛 \end{aligned}
======i1=l∑r...in=l∑r[(i1....in)=k]i1=⌈kl⌉∑⌊kr⌋...in=⌈kl⌉∑⌊kr⌋[(i1....in)=1]令l=⌈kl⌉,r=⌊kr⌋i1=l∑r...in=l∑r[(i1....in)=1]i1=l∑r...in=l∑rd∣(i1...i2)∑μ(d)d=1∑ri1=l∑r...in=l∑r[d∣(i1...in)]μ(d)d=1∑rμ(d)i1=l∑r[d∣i1]...in=l∑r[d∣in]只要另ij是d的倍数就满足d∣(i1...in)d=1∑rμ(d)(⌊dr⌋−⌊dl−1⌋)n分块+杜教筛
注意
分块时考虑
d
>
l
−
1
d>l-1
d>l−1的情况,会除
0
0
0
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,l,r;
const ll maxn=1e7;//预处理量
const ll mod=1e9+7;
map<ll,ll> mp_mu;
ll vis[maxn+2],p[maxn],mu[maxn+2],tot=0,mu_sum[maxn+2];
void init(){//预处理
mu[1]=1;
for(int i=2;i<=maxn;i++){
if(!vis[i]) p[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*p[j]<=maxn;j++){
vis[i*p[j]]=1;
if(i%p[j]==0){
mu[i*p[j]]=0;
break;
}
mu[i*p[j]]=-mu[i];
}
}
}
ll qpow(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=(a*a)%mod;
n>>=1;
}
return ans;
}
ll getMu(ll x){
if(x<=maxn) return mu_sum[x];
if(mp_mu.find(x)!=mp_mu.end()) return mp_mu[x];
ll res=1ll;
for(ll i=2,j;i<=x;i=j+1){
j=x/(x/i);
res-=getMu(x/i)*(j-i+1);
}
return mp_mu[x]=res;
}
ll du(ll L,ll R){//杜教筛
ll res=0;
for(int i=1,j;i<=R;i=j+1){
if(L-1<i) j=R/(R/i);//防止除零意外
else j=min(R/(R/i),(L-1)/((L-1)/i));//取小的那个:毕竟是分块嘛
ll x=getMu(j)-getMu(i-1);
ll y=qpow(R/i-(L-1)/i,n);
res=(res+(x*y)%mod)%mod;
}
res=(res+mod)%mod;//要是正才行
return res;
}
int main(){
int L,R;
init();
scanf("%lld%lld%d%d",&n,&k,&L,&R);
l=(L+k-1)/k;r=R/k;
for(int i=1;i<=min(r,maxn);i++) mu_sum[i]=mu_sum[i-1]+mu[i];
ll ans=du(l,r);
printf("%lld\n",ans);
}