UVa 11440 Help Tomisu 欧拉函数

来源:互联网 发布:sql identity是什么 编辑:程序博客网 时间:2024/05/22 05:29
链接

题意:求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) {;}
代码

 

原创粉丝点击