题意:
在[L,H]中选n个可重复,有序的数,使这些数的gcd=k。
题解:
1A了很爽。
莫比乌斯反演+杜教筛。
先转化题意,设
lk=⌊l−1k⌋+1 rk=⌊rk⌋
相当于在[lk,rk]中选n个互质的数。
即
ans=∑a1lk rk∑a2lk rk……∑a1lk rk[gcd(a1,a2,……,an)=1]
反演一波就得到
ans=∑irkμ(i)∗(⌊rki⌋−⌊lk−1i⌋)n
然后杜教筛求
μ
的前缀和就可以了。杜教筛
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
LL mu[5000010],prime[5000010];
bool v[5000010];
map<int,LL> sum;
int n,k,l,r,pr;
const LL mod=1000000007;
void pre()
{
memset(v,true,sizeof(v));
pr=0;mu[1]=1;
for(int i=2;i<=5000000;i++)
{
if(v[i]) prime[++pr]=(LL)i,mu[i]=(LL)(-1);
for(int j=1;j<=pr&&(LL)i*prime[j]<=5000000;j++)
{
v[i*prime[j]]=false;
if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
mu[0]=0;
for(int i=1;i<=5000000;i++) mu[i]=(mu[i]+mu[i-1])%mod;
}
LL solve(int n)
{
if(n<=5000000) return mu[n];
if(sum[n]) return sum[n];
LL ans=1LL;int j;
for(int i=2;i<=n;i=j+1)
{
j=n/(n/i);
ans=(ans-solve(n/i)*(j-i+1))%mod;
}
sum[n]=ans;
return ans;
}
LL work(LL a,int b)
{
LL ans=1LL;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans;
}
int main()
{
pre();sum.clear();
scanf("%d %d %d %d",&n,&k,&l,&r);
l=(l-1)/k+1;r/=k;//l=max(l,1);r=max(r,1);
LL ans=0LL;int j;
for(int i=1;i<=r;i=j+1)
{
//ans=(ans+mu[i]*work((r/i-(l-1)/i),n))%mod;
//printf("%d %lld\n",i,ans);
j=r/(r/i);
if((l-1)/i) j=min(j,(l-1)/((l-1)/i));
ans=(ans+(solve(j)-solve(i-1))*work((r/i-(l-1)/i),n))%mod;
}
printf("%lld",(ans+mod)%mod);
}