UVa 11440 Help Tomisu 欧拉函数

链接

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

 

posted @ 2017-09-22 17:40  拿叉插猹哈  阅读(138)  评论(0编辑  收藏  举报