题目描述
我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。
输入输出格式
输入格式:
输入一行,包含4个空格分开的正整数,依次为N,K,L和H。
输出格式:
输出一个整数,为所求方案数。
输入输出样例
2 2 2 4
3
说明
样例解释
所有可能的选择方案:(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4)
其中最大公约数等于2的只有3组:(2, 2), (2, 4), (4, 2)
对于100%的数据,1<=N,K<=10^9,1<=L<=H<=10^9,H-L<=10^5
此题有巧解
首先将L/k,R/k,gcd=k/k=1
令f(x)为gcd=x的方案数
F(i)为x能被i整除的方案数
F(i)=∑df(d) (i|d)
反演得f(d)=∑iμ(i/d)F(i) (d|i)
f(1)=∑μ(i)F(i) (1<=i<=H)
=∑μ(i)([r/i]-[(l-1)/i])^n
可知当i>H-L时,[r/i]-[(l-1)/i]等于1或0,所以可以去掉指数
f(1)=∑μ(i)([r/i]-[(l-1)/i])+∑μ(j)([r/j]-[(l-1)/j])^n (H-L+1<=i<=H,1<=j<=H-L)
因为H-L很小,直接枚举加快速幂搞定,对于左边
∑μ(i)([r/i]-[(l-1)/i]) (H-L+1<=i<=H)
=∑μ(i)([r/i]-[(l-1)/i])-∑μ(j)([r/j]-[(l-1)/j]) (1<=i<=H,1<=j<=H-L)
右边快速幂,而∑μ(i)([r/i]-[(l-1)/i])可以等价于取一个数,使gcd=1的方案数,显然只有当L=1时+1
复杂度为O((H-L)*log(n))
似乎此题还可以用递推??
1 #include2 #include 3 #include 4 #include 5 using namespace std; 6 int Mod=1000000007; 7 typedef long long lol; 8 bool vis[100001]; 9 lol mu[100001],r,l,n,k,ans;10 int tot,prime[100001];11 lol qpow(lol x,lol y)12 {13 lol res=1;14 while (y)15 {16 if (y%2==1)17 {18 res=(res*x)%Mod;19 }20 x=(x*x)%Mod;21 y=y/2;22 }23 return res;24 }25 void mobius()26 {lol i,j;27 mu[1]=1;28 for (i=2;i<=r-l;i++)29 {30 if (vis[i]==0)31 {32 tot++;33 prime[tot]=i;34 mu[i]=-1;35 }36 for (j=1;j<=tot,i*prime[j]<=r-l;j++)37 {38 vis[i*prime[j]]=1;39 if (i%prime[j]==0)40 {41 mu[i*prime[j]]=0;42 break;43 }44 mu[i*prime[j]]=-mu[i];45 }46 }47 }48 int main()49 { int i;50 cin>>n>>k>>l>>r;51 l=(l+k-1)/k;r=r/k;52 mobius();53 for (i=1;i<=r-l;i++)54 {55 ans=(ans+mu[i]*qpow(r/i-(l-1)/i,n)%Mod)%Mod; 56 }57 if (l==1) ans++;58 for (i=1;i<=r-l;i++)59 {60 ans=(ans-mu[i]*(r/i-(l-1)/i))%Mod; 61 }62 cout<<(ans+Mod)%Mod;63 }