BZOJ4802:欧拉函数(Pollard-Rho,欧拉函数)

Description

已知N,求phi(N)

Input

正整数N。N<=10^18

Output

输出phi(N)

Sample Input

8

Sample Output

4

Solution

一开始读错题了……以为是求约束个数和……

读对题之后然后发现我不会就问旁边的宽嫂……

宽嫂:这不是欧拉函数的定义式么?我初中就会了啊。

我:

然后去百度了一发,发现一个数的欧拉函数就是

$\prod (p_i-1)*p_i^{k_i-1}$,其中$p_i$是这个数的质因子,$k_i$是这个质因子的次数……

然后套板子就行了。

发现我之前抄了个假的快速乘然后还花了我一会儿改代码+改博客……QAQ

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<map>
 5 #include<algorithm>
 6 #define LL long long
 7 using namespace std;
 8 
 9 LL n,ans=1,Num[109],cnt;
10 LL prime[15]={2,3,5,7,11,13,17,19,23,29,31};
11 map<LL,LL>Keg;
12 
13 LL Mul(LL a,LL b,LL MOD)
14 {
15     LL tmp=a*b-(LL)((long double)a*b/MOD+0.1)*MOD;
16     return tmp<0?tmp+MOD:tmp;
17 }
18 
19 LL Qpow(LL a,LL b,LL MOD)
20 {
21     LL ans=1;
22     while (b)
23     {
24         if (b&1) ans=Mul(ans,a,MOD);
25         a=Mul(a,a,MOD); b>>=1;
26     }
27     return ans;
28 }
29 
30 LL gcd(LL a,LL b) {return b==0?a:gcd(b,a%b);}
31 
32 bool Miller_Rabin(LL n)
33 {
34     if (n==2) return 1;
35     if (n<2 || n%2==0) return 0;
36     LL m=n-1,l=0;
37     while (m%2==0) m>>=1, l++;
38     for (int i=0; i<11; ++i)
39     {
40         LL p=prime[i],w=Qpow(p,m,n);
41         if (w==n-1 || w==1 || p==n) continue;
42         for (int j=1; j<=l; ++j)
43         {
44             LL u=Mul(w,w,n);
45             if (u==1 && w!=n-1 && w!=1) return 0;
46             w=u;
47         }
48         if (w!=1) return 0;
49     }
50     return 1;
51 }
52 
53 LL Pollard_Rho(LL n,LL c)
54 {
55     LL x=(rand()+1)%n,y=x,p=1,k=2;
56     for (LL i=1; p==1; ++i)
57     {
58         x=(Mul(x,x,n)+c)%n;
59         p=x>y?x-y:y-x;
60         p=gcd(p,n);
61         if (i==k) y=x, k=k+k;
62     }
63     return p;
64 }
65 
66 void Solve(LL n)
67 {
68     if (n==1) return;
69     if (Miller_Rabin(n))
70     {
71         if (!Keg[n]) Num[++cnt]=n;
72         ++Keg[n]; return;
73     }
74     LL t=n;
75     while (t==n) t=Pollard_Rho(n,rand()%(n-1)+1);
76     Solve(t); Solve(n/t);
77 }
78 
79 int main()
80 {
81     scanf("%lld",&n);
82     Solve(n);
83     for (int i=1; i<=cnt; ++i)
84         ans=ans*(Num[i]-1)*Qpow(Num[i],Keg[Num[i]]-1,2e18);
85     printf("%lld\n",ans);
86 }
posted @ 2018-12-13 17:55  Refun  阅读(227)  评论(0编辑  收藏  举报