int n; cin>>n; int ans = n; for(int i = 2; i <= n/i; i++){ if(n % i == 0){ ans = ans / i * (i-1); while(n % i == 0){ n /= i; } } } if(n > 1) ans = ans / n *(n-1); cout<<ans<<endl;
筛法求欧拉函数
在筛法求素数的过程中间接得到欧拉函数
当 n 为素数的时候 ϕ(n)=n−1
当 $ n \quad mod \quad primes[ j ] = 0 $时 说明 primes[j] 时 n的一个质因子,
这时候我们来看 ϕ(i) 与 ϕ(i×primes[j]) 的关系不难发现:i×primes[j] 与 i 的只多了一个 $ primes[ j ] $ 倍,而且 $ primes[ j ] $ 本就是 i 的一个质因子故 i×primes[j] 与 i 有着相同的因数,只是在分解质因数后 primes[j] 的指数项不同 ,
又欧拉函数ϕ(n)=n(1−ρ11)(1−ρ21)...(1−ρn1)
与分解因数后的指数项无关,故 ϕ(i) 与 ϕ(i×primes[j]) 求值时只有第一项 n 的区别
intqmi(int a, int k, int p){ int ans = 1; while(k){ if(k&1) ans = (LL)ans * a % p; k >>= 1; a = (LL)a * a % p; } return ans; }
快速幂求逆元
逆元的定义:
若整数 b ,m 互质, 并且对于任意的整数 a 都存在一个整数 x 使得 ba≡a×x(modm) 则称 x 为 b 的模 m 的乘法逆元,记作 $ b^{-1} \ \ (mod \ \ m)$ 。
b 存在关于 m 的逆元的充要条件是 b 与 m 互质,当 m 为质数时, bm−2 即为 b 的乘法逆元
当 m 为质数时的证明:
$ \frac{a}{b} \ \equiv \ a b^{-1} \ (mod \ \ m) $
两边同乘 b
$ a \ \equiv \ a \ b \ b^{-1}\ (mod \ \ m) $
$ \Rightarrow b \ b^{-1}\ \equiv \ 1 \ (mod \ \ m) $
又m为质数 由费马小定理可得
bm−1≡1(modm)
故当 b 关于 m 的乘法逆元 b−1=bm−2
核心代码:
1 2 3 4 5 6 7 8
//当m为质数时 (这时用p表示m) //注意这里判断 impossible 的条件不能是 ans 是否为0 //因为当p为2时不能判断b是否与p互质 qmi(b, p-2, p) 一定返回 1 int b, p; scanf("%d%d",&b, &p); int ans = qmi(b, p-2, p); if(b % p) cout<<ans<<endl; else cout<<"impossible"<<endl;
逆元存在的意义就是将除法取模转化为乘法取模
扩展欧几里得定理
裴蜀定理
若有一对正整数a,b ,那么一定存在非零整数x, y, 使得ax + by = gcd(a, b) 并且gcd(a, b) 是 ax + by 能得到的最小的正整数
证明:提取(ax + by)的最大公倍数 gcd(a, b) 所得正整数也一定是 gcd(a, b)的整数倍 故最小值为 gcd(a, b)
扩展欧几里得定理
证明:
先看边界状态当b = 0 时, a与0的最大公约数为a 故 a×1+b×0=gcd(a,b) 此时 x = 1, y = 0 为一组解
看一个状态的后一个状态与当前状态,
后一个状态:$ b\ \times\ y \ + \ (a \ \ mod \ \ b) \ \times \ x = gcd(a, \ b)$
当前状态:$a \ \times\ x\ + \ b\ \times\ y = gcd(a,\ b) $
现在找到后一个状态与前一个状态的区别讲后一个状态化简:
首先 $(a \ \ mod \ \ b) = a \ - [a \ \div\ b ] \times b $ 这里的除法为整除
$ b\ \times\ y \ + \ (a \ \ mod \ \ b) \ \times \ x$
$ = b \ \times\ y + (a \ - [a \ \div\ b ] \times b) x$
$ = a \ \times\ x \ +\ b\ \times\ (y\ -\ [a \ \div\ b ]\ \times\ x) $
也就是前一个状态下求得的 x 与 y 值要在当前状态下成立需要将
x→x
y→(y−[a÷b]×x)
核心代码:
1 2 3 4 5 6 7 8 9
intexgcd(int a, int b, int &x, int &y){ if(!b){ x = 1, y = 0; return a; } int d = exgcd(b, a%b, y, x); y -= a/b*x; return d; }
注意这里求得的 x 与 y 是不唯一的
线性同余方程
描述:给定一组数据 a , b , m , 对于这组数据求一个 x , 使其满足 $a \ \times \ x \ \equiv \ b \ \ (mod \ \ m) $ 如果无解则输出impossible
将方程转换为裴蜀定理的形式
$a \ \times \ x \ \equiv \ b \ \ (mod \ \ m) $
$ \Rightarrow a \ \times \ x \ - \ b \ \equiv \ 0 \ \ (mod \ \ m) $
即 a×x−b 是 m 的整数倍
即存在整数 y 使得 $\Rightarrow a \ \times \ x \ - \ b \ = \ m \ \times \ y $
进一步 $\Rightarrow a \ \times \ x \ + \ m \ \times \ (-y) \ = \ b $
方程已转化为 裴蜀定理 的形式
并且由裴蜀定理可知 当且仅当 b 是 gcd(a,m) 的整数倍时方程有解
1 2 3 4 5 6
//这里为了使结果在int范围内将 x*(b/d)与m取模 这个结论成立可以从原始方程中得到 int a, b, m, x, y; scanf("%d%d%d", &a, &b, &m); int d = exgcd(a, m, x, y); if(b % d) printf("impossible\n"); elseprintf("%d\n", (longlong)x*(b/d) % m);