https://loj.ac/problem/2544
自己太傻,一遇到有关数学的题就懵逼,这种简单题竟然还得靠NicoDafaGood
在$[l,r]$这个区间内,如果没有数是$x$的因数,我们称$x$为好数。
我们就只需要考虑这些好数中最靠后的那一个的位置,因为这些好数,我们必须取,而且是充分必要条件。
那么我们算得了好数的个数,问题就转化成,有一堆0和1,问所有排列方式,最后一个1的位置的和。
或者说,算最后的连续的0的个数的和。
明显可以随便递推转移一下。
//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
const ll mod=1e9+7,maxn=1e7+7;
ll n,m,dp[maxn],mi[maxn];char cc;ll ff;
template<typename T>void read(T& aa) {aa=0;cc=getchar();ff=1;while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();if(cc=='-') ff=-1,cc=getchar();while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();aa*=ff;
}int prime[maxn],num[maxn],totp;
bool ok[maxn];
void get_p() {num[1]=2;For(i,2,m) {if(!ok[i]) num[i]=i,prime[++totp]=i;For(j,1,totp) {if(prime[j]>m/i) break;ok[i*prime[j]]=1;num[i*prime[j]]=prime[j];if(i%prime[j]==0) break;}}
}int main() {read(n); read(m);get_p(); ll x,sum=0,o=m-n+1;For(i,n,m) {x=i/num[i];if(x<n) ++sum;}dp[0]=1; o-=sum;For(i,1,o) dp[i]=dp[i-1]*(o-i+1)%mod;mi[0]=1; For(i,1,o+sum) mi[i]=mi[i-1]*i%mod;For(i,0,o) dp[i]=dp[i]*mi[sum+o-i]%mod;For(i,0,o) dp[i]=(dp[i]-dp[i+1]+mod)%mod;ll rs=0; For(i,0,o) rs+=dp[i]*(sum+o-i)%mod;printf("%lld\n",rs%mod);return 0;
}