1. 程式人生 > >【bzoj4802】尤拉函式

【bzoj4802】尤拉函式

題目連結

想瞎搞過去的可能就只有我一個。。。。。

正解Pollard_rho演算法(啥rho演算法?)

Pollard_rho演算法是專門解決這類大數質因數分解的,當然還要搭配Miller_Rabin判素數(推薦一篇入門博文

先質因數分解,然後按 φ ( i )

的式子算就行了

程式碼:

#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long LL;

const int INF = 2147483647
; const int maxn = 10000000; LL ans; LL n,pri[maxn],tot,tme = 0; inline LL getint() { LL ret = 0,f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar(); return
ret * f; } inline LL mul(LL x,LL y,LL mod) { LL tmp=(x*y-(LL)((long double)x/mod*y+1.0e-8)*mod); return tmp<0 ? tmp+mod : tmp; } inline LL qpow(LL a,LL b,LL n) { LL ret = 1; while (b) { if (b & 1) ret = mul(ret,a,n); a = mul(a,a,n); b >>= 1; } return ret; } inline int miller(LL n) { int test; if (n == 3) test = 1; if (n == 2) return 1; if (n < 2 || n % 2 == 0) return 0; LL m = n - 1,k = 0; while (m % 2 == 0) m >>= 1 , k++; for (int I = 1; I <= 5; I++) { LL a = rand() % (n - 1) + 1,b; a = qpow(a,m,n); for (int i = 1; i <= k; i++) { b = mul(a,a,n); if (b == 1 && a != n - 1 && a != 1) return 0; a = b; } if (a != 1) return 0; } return 1; } inline LL gcd(LL a,LL b) { return !b ? a : gcd(b,a % b); } inline LL rho(LL n) { LL x = rand() % (n - 1) + 1,y = x; LL c = tme % (n - 1) + 1,g,k = 2,i = 0; tme++; while (233) { x = (mul(x,x,n) + c) % n; if (x == y) return n; g = gcd(abs(x - y),n); if (g != 1) return g; if (++i == k) y = x , k <<= 1; } } inline void split(LL n) { if (n == 1) return; if (miller(n)) {pri[++tot] = n; return;} LL p = n; while (p == n) p = rho(p); split(n / p); split(p); } int main() { #ifdef AMC freopen("AMC1.txt","r",stdin); #endif n = getint(); split(n); sort(pri + 1,pri + tot + 1); ans = 1; for (int i = 1; i <= tot; i++) { if (pri[i] != pri[i - 1]) ans *= pri[i] - 1; else ans *= pri[i]; } printf("%lld\n",ans); return 0; }