您的位置:首页 > 其它

UVa 11440 Help Tomisu 欧拉函数

2017-10-15 14:00 435 查看
链接
题意:求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) {;}


代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: