嘛,主要是为了学杜教筛
然后发现其实可以背板子?
莫比乌斯函数前缀和
欧拉函数前缀和
那么就假装会用杜教筛求比较大的莫比乌斯函数的前缀和了
这个时候愉快地用莫比乌斯反演推出公式
整除分块一波就可以过了
代码如下:
#include<bits/stdc++.h>
#define N 2000010
#define mod 1000000007
using namespace std;
int vis[N],p[N],mu[N];
int n,k,g,h,cnt;
map<int,int> m;
int init()
{
vis[1]=1;
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
mu[i]=-1;
p[++cnt]=i;
}
for(int j=1;j<=cnt;j++)
{
if(p[j]*i>=N) break;
vis[i*p[j]]=1;
if(!(i%p[j]))
{
mu[i*p[j]]=0;
break;
}
else
{
mu[i*p[j]]=-mu[i];
}
}
}
}
long long kasumi(long long a,long long b)
{
long long ans=1ll;
while(b)
{
if(b&1) ans=a*ans%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
long long solve(long long x)
{
if(x<N) return mu[x];
if(m.count(x)) return m[x];
long long res=0,lim=sqrt(x);
for(int i=2;x/i>lim;i++)
{
res+=solve(x/i);
}
for(int i=lim;i>=1;i--)
{
res+=(x/i-x/(i+1))*solve(i);
}
m[x]=1-res;
return 1-res;
}
int main()
{
init();
for(int i=1;i<N;i++)
{
mu[i]+=mu[i-1];
}
scanf("%d%d%d%d",&n,&k,&g,&h);
g--;
long long ans=0;
g/=k;
h/=k;
int l,r;
for(l=1,r;l<=max(g,h);l=r+1)
{
if(g<l) break;
r=min(h/(h/l),g/(g/l));
ans+=1ll*(solve(r)-solve(l-1)) *kasumi(h/l-g/l,n)%mod;
ans=(ans+mod)%mod;
}
for(;l<=h;l=r+1)
{
r=h/(h/l);
ans+=1ll*(solve(r)-solve(l-1))*kasumi(h/l,n)%mod;
ans=(ans+mod)%mod;
}
printf("%lld\n",ans);
}