学数学要自己手推一遍
欧拉定理
若a与m互质,则 a^(Φ(m))模m同余1
公式如下:
费马小定理
欧拉函数
Φ(x)
1~n中与n互质的数的个数
1 ~ n中pk 的倍数的个数是 N/pk
如何算1~n中与n互质的数的个数?
- 从1~n中去掉p1、p2……pk的所有倍数
- 加上所有pi*pj的倍数
- 减去所有pipjpk的倍数
求欧拉函数 O(nsqrt(n))
int phi(int x)
{
int res = x;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
res = res / i * (i - 1);
while (x % i == 0) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return res;
}
筛法求欧拉函数
int primes[N], cnt; // primes[]存储所有素数
int euler[N]; // 存储每个数的欧拉函数
bool st[N]; // st[x]存储x是否被筛掉
void get_eulers(int n)
{
euler[1] = 1;
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
primes[cnt ++ ] = i;
euler[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++ )
{
int t = primes[j] * i;
st[t] = true;
if (i % primes[j] == 0)
{
euler[t] = euler[i] * primes[j];
break;
}
euler[t] = euler[i] * (primes[j] - 1);
}
}
}
快速幂 O(logk)
模板:
求 m^k mod p,时间复杂度 O(logk)。
int qmi(int m, int k, int p)
{
int res = 1 % p, t = m;
while (k)
{
if (k&1) res = res * t % p;
t = t * t % p;
k >>= 1;
}
return res;
}
快速幂求逆元
裴蜀定理
有一对正整数a、b,那么一定存在整数x、y,使得 ax + by = gcd(a,b)
扩展欧几里得
若 ax = b ( mod m ) 有解 <--> 存在y 使得 ax = my + b
模板:
// 求x, y,使得ax + by = gcd(a, b)
int exgcd(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;
}
中国剩余定理
扩展欧几里得来求逆