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^5Solution
我用的是莫比乌斯反演加杜教筛
这题本来不需要莫反的,但最近都在练习莫反,那就用莫反做了 设\(F(d)\)代表在\([L,R]\)中选N个数,它们的gcd为d及其倍数的方案数 设\(f(d)\)代表在\([L,R]\)中选N个数,它们的gcd为d的方案数\[F(n)=\sum_{n|d}f(d)=(\lfloor \frac{R}{n} \rfloor-\lfloor \frac{L-1}{n} \rfloor)^N\] 上面式子的左边一半根据定义,右边一半的原因如下:\(\lfloor \frac{R}{n} \rfloor\)其实是1到R中有多少个数整除n,\(\lfloor \frac{L-1}{n} \rfloor\)类似,那么它们相减之后,得到的就是\([L,R]\)中有多少个数可以整除n。根据题目的第一句话,我们知道选数是有序的,并且可以重复选。所以我们在得到了有多少个数整除n后,只要在里面有序地任选N个数,方案数是\((\lfloor \frac{R}{n} \rfloor-\lfloor \frac{L-1}{n} \rfloor)^N\),它们可以保证它们的gcd一定为n或n的倍数 接下来继续推\[f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)=\sum_{n|d}\mu(\frac{d}{n})(\lfloor \frac{R}{d} \rfloor-\lfloor \frac{L-1}{d} \rfloor)^N\] 改变枚举方式\[f(n)=\sum_{d=1}^{\lfloor \frac{R}{n} \rfloor}\mu(d)(\lfloor \frac{R}{nd} \rfloor-\lfloor \frac{L-1}{nd} \rfloor)^N\] 后面的东西整除分段加快速幂,前面的东西杜教筛 关于杜教筛,这里只给一个式子,有兴趣可以百度\[S(n)=1-\sum_{i=2}^nS(\lfloor \frac{n}{i} \rfloor)\ \ \ \ (S(n)=\sum_{i=1}^n\mu(i))\]#include#define ll long longconst int Mod=1e9+7,MAXN=1e6+10,inf=0x3f3f3f3f;int prime[MAXN],cnt,vis[MAXN],s[MAXN],mu[MAXN];std::map M;template inline void read(T &x){ T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w;}template inline void write(T x,char c='\0'){ if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(c!='\0')putchar(c);}template inline void chkmin(T &x,T y){x=(y inline void chkmax(T &x,T y){x=(y>x?y:x);}template inline T min(T x,T y){return x inline T max(T x,T y){return x>y?x:y;}inline void init(){ memset(vis,1,sizeof(vis)); vis[0]=vis[1]=0; mu[1]=1; for(register int i=2;i >=1; } return res;}inline ll MuSum(int x){ if(x x)break; int j=x/(x/i); res-=(ll)(j-i+1)*(ll)MuSum(x/i); i=j+1; } return M[x]=res;}inline ll solve(int N,int L,int H){ ll res=0; for(register int i=1;;) { if(i>H)break; int j=min(H/(H/i),L/i?L/(L/i):inf); (res+=qexp((ll)(H/i-L/i),N)*(ll)(MuSum(j)-MuSum(i-1))%Mod)%=Mod; i=j+1; } return (res+Mod)%Mod;}int main(){ init(); int N,K,L,H; read(N);read(K);read(L);read(H); write(solve(N,(L-1)/K,H/K),'\n'); return 0;}