正题
题目链接给一下
题目已经很明显了,要我们求
还是变形一下,
然后套路反演
因为H很大,所以前缀和用杜教筛求就好了,然后整除分块,大概时间复杂度就是非线性的吧。
#include
#include
#include
#include
#include
点开题解,发现有一种很神的Dp做法。
首先,还是得到这条公式
我们怎么让他的gcd为1呢,或者说,我们怎么知道gcd为1的有多少对呢?
用记录x在中是多少个组合的最大公约数。
暂且让,dx为x在这个区间内出现的次数,那么现在为不包括相同数字的组合,而且最大公约数为x的倍数的组合个数。
那么因为,所以干脆不记录。
然后倒着做一次就可以了。
#include
#include
#include
#include
#include
using namespace std;
int n,k,l,r;
long long mod=1e9+7;
long long f[1000010];
long long ksm(long long x,long long t){
long long tot=1;
while(t){
if(t%2) (tot*=x)%=mod;
(x*=x)%=mod;
t/=2;
}
return tot;
}
int main(){
scanf("%d %d %d %d",&n,&k,&l,&r);
l=ceil((double)l/k),r=floor((double)r/k);
int a,b;
for(int i=1;i<=r-l;i++){
a=ceil((double)l/i);b=floor((double)r/i);
f[i]=(ksm(b-a+1,n)-(b-a+1)+mod)%mod;
}
if(l==1) f[1]++;
for(int i=r-l;i>=1;i--){
for(int j=2*i;j<=r-l;j+=i) f[i]-=f[j];
(f[i]=f[i]%mod+mod)%=mod;
}
printf("%lld",f[1]);
}