题目描述
我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。
题解
首先转化一下,变成求[L/k,R/k]的答案,此时公约数就变成了1。
但这样我们还是不能直接枚举GCD,它的范围是1e9的。
考虑区间长度最大为1e5,说明其中任意两个不同的数的GCD是要小于区间长度的。
所以我们设f[i]表示从区间中选n不完全相同的数GCD为i的方案数。
按照套路容斥一下。
代码
#include<iostream> #include<cstdio> #define N 100002 using namespace std; typedef long long ll; const int mod=1000000007; ll f[N],n,k,l,r; inline ll rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } inline ll power(ll x,ll y){ ll ans=1; while(y){ if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1; } return ans; } int main(){ n=rd();k=rd();l=rd();r=rd(); r=r/k;l=(l-1)/k; for(int i=r-l;i>=1;--i){ int x=(r/i-l/i+mod)%mod; f[i]=(power(x,n)-(x)+mod)%mod; for(int j=i*2;j<=r-l;j+=i)f[i]=(f[i]-f[j]+mod)%mod; } if(!l)f[1]=(f[1]+1)%mod; cout<<f[1]; return 0; }