Description
我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。
Input
输入一行,包含4个空格分开的正整数,依次为N,K,L和H。
Output
输出一个整数,为所求方案数。
解题报告:老套路设(f_i)表示gcd为i的方案数,转化为求[L/K,R/K]中互质的数对个数,答案即为(f_1),考虑这一题数据范围较大,且(H-L<=10^5),那么就需要用到结论:假设N个数不全相同,那么他们的最大公约数小于最大和最小的两个数之差,正确性显然,所以我们把状态改为:(f_i)表示选n个互不相同的数,gcd为i的方案数
令L=L/K,R=R/K
那么[L,R]间含i这个因子的数有(R/i)-((L-1)/i)种,所以选n个的方案数一共有((R/i-(L-1)/i)^n),再减去所有数都重复的((R/i-(L-1)/i))种,减完之后的值设为(tot),然后就是推(fi),因为现在的方案只是包含i这个因子,而不是gcd=i的方案,所以还要减去gcd不为i的方案
综上:(f_i=tot-sum_{j=i*2}^{j=R-L}f_j)
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=1e5+5,mod=1000000007;
ll qm(ll x,ll k){
ll sum=1;
while(k){
if(k&1)sum*=x,sum%=mod;
x*=x;x%=mod;k>>=1;
}
return sum;
}
ll f[N];
void work()
{
int n,L,R,K;
cin>>n>>K>>L>>R;
bool flg=(L<=K && K<=R);
L--;L/=K;R/=K;int c=R-L;
ll l,r;
for(int i=c;i>=1;i--){
l=L/i;r=R/i;
f[i]=((qm(r-l,n)-(r-l)%mod)+mod)%mod;
for(int j=2;j*i<=c;j++)
f[i]-=f[j*i],f[i]=(f[i]%mod+mod)%mod;
}
f[1]+=flg;f[1]%=mod;
printf("%lld
",f[1]);
}
int main()
{
work();
return 0;
}