Description
我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。
Input
输入一行,包含4个空格分开的正整数,依次为N,K,L和H。
Output
输出一个整数,为所求方案数。
Sample Input
2 2 2 4
Sample Output
3
Hint
样例解释
所有可能的选择方案:(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,r]间选择n个元素,且它们的gcd为k*i的选择方案是f[i]。
显然,[l,r]内能被k*i整除的数有(R-L)^n个(R=r/(i*k),L=(l-1)/(i*k))。但是,有一些选择是这种(a,a,a,a,a,….a),一共有(R-L)种,同时还有最大公约数是k*i的倍数的,我们也要减去。
从后往后递推即可。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define mod 1000000007
LL f[100005];
LL quick_pow(LL a,LL n){
LL ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
int main(){
LL N,K,L,H;
while(cin>>N>>K>>L>>H){
memset(f,0,sizeof(f));
for(int i=100005;i>=1;i--){
LL x=(L-1)/(i*K);
LL y=H/(i*K);
f[i]=quick_pow(y-x,N);
f[i]=(f[i]-(y-x)+mod)%mod;
for(int j=i+i;j<100005;j+=i) f[i]=(f[i]-f[j]+mod)%mod;
}
if(K>=L&&K<=H) f[1]++;
cout<<(f[1]%mod)<<endl;
}
return 0;
}