此题的容斥解法首先要基于一个看似神奇但实则显然的定理:
在一个区间长度为
l
e
n
len
len的区间任意取n个数,其中n个数不完全相同,则这n个数的gcd一定满足:
g
c
d
<
=
l
e
n
gcd <= len
gcd<=len
故我们可以进行递推容斥。
首先假设取的n个数完全相同,若存在其
g
c
d
gcd
gcd等于
k
k
k的情况,则k一定满足:
l
<
=
k
<
=
r
l <= k <= r
l<=k<=r且n个数只能全是k,故如果满足条件,该方案数一定是1。故可提前特判。
当n个数不完全相同时,设:
a
[
i
]
:
a[i]:
a[i]:在
[
l
,
r
]
[l,r]
[l,r]区间取
n
n
n个数,其
g
c
d
=
=
k
∗
i
gcd == k*i
gcd==k∗i的方案数。
故
a
[
1
]
a[1]
a[1] + 特判即为答案。
对于a数组,我们可以倒着递推:
设
l
e
n
=
r
k
i
−
(
l
−
1
)
k
i
len =\frac{r}{ki} -\frac{(l-1)}{ki}
len=kir−ki(l−1)
a
[
i
]
=
l
e
n
n
−
l
e
n
−
(
a
[
2
i
]
+
a
[
3
i
]
+
.
.
.
.
)
a[i] = len^n - len - (a[2i] + a[3i] + ....)
a[i]=lenn−len−(a[2i]+a[3i]+....)
减去len是减去取的n个数完全一样的方案数。
故此题可解。
代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int A = 1e5 + 10;
ll a[A];
ll fast_mod(ll n,ll m){
ll res = 1;
while(m){
if(m&1) res = (res*n)%mod;
n = (n*n)%mod;
m >>= 1;
}
return res;
}
int main(){
int n,k,l,r;
ll ans = 0;
scanf("%d%d%d%d",&n,&k,&l,&r);
if(l<=k && k<=r) ans++; //特判n个数全选k使gcd == k的情况
int len = (r-l+1);l--;
l /= k,r /= k;
for(int i=len ;i>=1;i--){
int x = l/i,y = r/i;
a[i] = (fast_mod(y-x,n) - (y-x))%mod;
for(int j=2*i ;j<=len ;j+=i) a[i] = (a[i]-a[j])%mod;
}
ans = (ans + a[1])%mod;
if(ans<0) ans+=mod;
printf("%lld\n",ans);
return 0;
}