题意:求2~n!中x的所有素因子大于m的x的个数
由x的所有素因子大于m可知
gcd(x,m!)==1
x中不含有任何一个小于m的素因子 那我们将m!和x写成素数相乘的形式 他们的gcd等于1
若x>m! 我们有 gcd(x,m!)==gcd(m!,x%m!)==1
也就是说x是m!简单剩余系中某一个数的倍数
我们有gcd(x,m!)==1 可以求出 x<m!的个数φ(m!) 即欧拉函数
要求在2~n!中x的个数 就是m!的简单剩余系的个数乘n!/m!
(关于简单剩余系 大家可以百度)
现在我们知道了 答案的计算方式 下面就是计算
由于n-m<=100000 阶乘完全可以循环处理
但是m!<=1e7 我们就从递推考虑
设 fact[i-1] =φ(i-1)
fact[i-1] = (i-1)! *(1-1/p1)*(1-1/p2).....(1-1/pk) k为素数个数
如果当前的i不是素数 就可以写成素数的乘积 不会使素数个数增加 fact[i]=fact[i]*i
如果当前的i为素数 阶乘多了一个m 后面多了一个(1-1/m) 两者相乘为 (m-1)
1 #include <cstdio> 2 #include <cctype> 3 4 typedef long long LL; 5 const int mod=1e8+7; 6 const int MAXN=10000001; 7 8 int n,m,tot; 9 10 int prime[MAXN/10]; 11 12 LL fact[MAXN]; 13 14 bool vis[MAXN]; 15 16 inline bool read(int&x) { 17 int f=1;register char c=getchar(); 18 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 19 for(;isdigit(c);x=x*10+c-48,c=getchar()); 20 return x=x*f; 21 } 22 23 inline void pre() { 24 for(int i=2;i<MAXN;++i) { 25 if(!vis[i]) prime[++tot]=i; 26 for(int j=1;j<=tot;++j) { 27 if(i*prime[j]>=MAXN) break; 28 vis[i*prime[j]]=true; 29 if(i%prime[j]==0) break; 30 } 31 } 32 return; 33 } 34 35 inline void Euler() { 36 fact[1]=fact[2]=1; 37 for(int i=3;i<MAXN;++i) 38 fact[i]=(fact[i-1]*(vis[i]?i:(i-1)))%mod; 39 return; 40 } 41 42 int hh() { 43 pre(); 44 Euler(); 45 while(read(n)&&read(m)) { 46 LL ans=fact[m]; 47 for(int i=m+1;i<=n;++i) 48 ans=(LL)(ans*i)%mod; 49 printf("%lld\n",(ans+mod-1)%mod); 50 } 51 return 0; 52 } 53 54 int sb=hh(); 55 int main(int argc,char**argv) {;}