题目传送门
题目大意: 从 [ L , H ] [L,H] [L,H] 中选 N N N 个数,可以重复选,问有多少种选法可以使得这 N N N 个数的 gcd \gcd gcd 为 k k k。
一看到 g c d gcd gcd 自然而然的就想到莫比乌斯反演了。
设 f ( d ) f(d) f(d) 表示有多少种选取方案的 gcd \gcd gcd 为 d d d, F ( n ) F(n) F(n) 表示有多少种选取方案的 gcd \gcd gcd 是 n n n 的倍数,那么有:
F ( n ) = ∑ n ∣ d f ( d ) F(n)=\sum_{n|d} f(d) F(n)=n∣d∑f(d)
反演一下得到:
f ( d ) = ∑ d ∣ n F ( n ) μ ( n d ) f(d)=\sum_{d|n}F(n)\mu(\frac n d)\\ f(d)=d∣n∑F(n)μ(dn)
设 i = n d i=\frac n d i=dn,更换枚举对象,有:
f ( d ) = ∑ i = 1 ⌊ H d ⌋ F ( i d ) μ ( i ) f(d)=\sum_{i=1}^{\lfloor \frac H d \rfloor} F(id)\mu(i) f(d)=i=1∑⌊dH⌋F(id)μ(i)
显然 F ( n ) = ( ⌊ H n ⌋ − ⌊ L − 1 n ⌋ ) N F(n)=(\lfloor \frac H n \rfloor-\lfloor \frac {L-1} n \rfloor)^N F(n)=(⌊nH⌋−⌊nL−1⌋)N,带进去得:
f ( d ) = ∑ i = 1 ⌊ H d ⌋ ( ⌊ H i d ⌋ − ⌊ L − 1 i d ⌋ ) N μ ( i ) f(d)=\sum_{i=1}^{\lfloor \frac H d \rfloor} (\lfloor \frac H {id} \rfloor-\lfloor \frac {L-1} {id} \rfloor)^N\mu(i) f(d)=i=1∑⌊dH⌋(⌊idH⌋−⌊idL−1⌋)Nμ(i)
变成了一个除法分块的形式,再用杜教筛筛一下 μ \mu μ 的前缀和就好了。
所以然而并不知道题目里面 H − L ≤ 1 0 5 H-L\leq 10^5 H−L≤105 这个条件用来干啥qwq。
代码如下:
#include
#include
#include
#include
using namespace std;
#define mod 1000000007ll
#define ll long long
#define maxn 6000010
int n,k,L,H;
int prime[maxn],t=0,mu[maxn];
bool v[maxn];
void work()
{
mu[1]=1;
for(int i=2;i<=maxn-10;i++)
{
if(!v[i])prime[++t]=i,mu[i]=-1;
for(int j=1;j<=t&&i*prime[j]<=maxn-10;j++)
{
v[i*prime[j]]=true;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
mu[i]+=mu[i-1];
}
}
int ksm(int x,int y)
{
int re=1,tot=x;
while(y>0)
{
if(y%2==1)re=(ll)re*tot%mod;
tot=(ll)tot*tot%mod;
y/=2;
}
return re;
}
map<int,int>mapmu;
int S(int x)
{
if(x<=maxn-10)return mu[x];
if(mapmu[x])return mapmu[x];
int re=1,l=2,r;
while(l<=x)
{
r=x/(x/l);
re-=S(x/l)*(r-l+1);
l=r+1;
}
mapmu[x]=re;
return re;
}
int main()
{
work();
scanf("%d %d %d %d",&n,&k,&L,&H);
L--;L/=k;H/=k;
int l=1,r,ans=0;
while(l<=H)
{
if(l<=L)r=min(L/(L/l),H/(H/l));
else r=H/(H/l);
ans=((ll)ans+(ll)ksm(H/l-L/l,n)*((ll)(S(r)-S(l-1)+mod)%mod)%mod)%mod;
l=r+1;
}
printf("%d\n",ans);
}