数论知识:
1、欧拉函数
欧拉函数 O(N)=1到N中所有与N互质的数的个数,如果可以把N写成它的分解质因数公式:
N=p1的a1次方 * p2的a2次方 * .....pk的ak次方
则它的欧拉函数等于N*(1-1/p1)*(1-1/p2)*...(1-1/pk),这是由容斥原理得到的(数学集合论),
我们将n减去所有它的因子的倍数,这其中有些数被减了两次,如p1,p2共同的倍数,我们再逐一加上每两个数的倍数,再减去每三个数的倍数...就能得到与N互质的数的个数了。
#include<iostream>
#include<algorithm>
using namespace std;
int n, res;
int main()
{
cin>>n;
while(n--)
{
int a;
cin>>a;
res = a;
for(int i=2;i<=a/i;i++)
{
if(a % i == 0)
{
res = res / i * (i - 1);
while(a % i == 0) a /= i;
}
}
if (a > 1) res = res / a * (a - 1);
cout<<res<<endl;
}
return 0;
}
筛法求欧拉函数:
质数的欧拉函数为本身减1,因为自己是质数,除1外每个数都是与自己互质的数。
而i*primesj的欧拉函数与i的欧拉函数的关系
如果i mod pj ==0的话,i的所有质因子也是i * pj的质因子,且i中已经计算过pj,所以就差个pj。
else pj是i的最小质因子,且i的欧拉函数里面没有计算过pj,所以差 pj * (1-1/pj)即(pj-1)。
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=1e6 + 10;
int primes[N], phi[N];
int cnt;
bool st[N];
LL getola(int n)
{
LL res = 0;
phi[1] = 1;
for(int i=2;i<=n;i++)
{
if(!st[i])
{
primes[cnt++] = i;
phi[i] = i-1;
}
for(int j=0;primes[j]<=n/i;j++)
{
st[i * primes[j]] = true;
if(i % primes[j] == 0)
{
phi[i * primes[j]] = phi[i] * primes[j];
break;
}
phi[i * primes[j]] = phi[i] * (primes[j] - 1);
}
}
for(int i=0;i<=n;i++)
{
res += phi[i];
}
return res;
}
int main()
{
int n;
cin>>n;
cout<<getola(n)<<endl;
return 0;
}
欧拉定理:
快速幂:可以快速的求出来a的k次方mod p 的结果(在logk时间下)
先预处理a的2的0次方mod p,a的2的1次方mod p。。。。,然后k分解为二进制是1的位求出来,找到这些数的预处理乘起来,就可以算出a的k次方mod p,。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL qmi(int a, int k, int p)
{
LL res = 1;
while(k)
{
if(k & 1) res = (LL) res * a % p;
k >>= 1;
a = (LL) a * a % p;//每一位都求对p的mod
}
return res;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a, k, p;
scanf("%d%d%d", &a, &k, &p);
cout<<qmi(a, k, p)<<endl;
}
return 0;
}
快速幂求逆元
有用到费马定理:b的p-1次方与1同余,所以b*b的p-2次方也与1同余,所以b的逆元为b的p-2次方(当m为质数p时成立)
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL qmi(int a, int k, int p)
{
LL res = 1;
while(k)
{
if(k & 1) res = (LL) res * a % p;
k >>= 1;
a = (LL) a * a % p;
}
return res;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a, p;
scanf("%d%d", &a, &p);
LL res = qmi(a, p-2, p);
if(a % p) cout<<res<<endl;
else puts("impossible");
}
return 0;
}
裴蜀定理:正整数a,b能凑出来的最小正整数一定是他们的最大公约数。
#include<iostream>
#include<algorithm>
using namespace std;
int exgcd(int a, int b, int &x, int &y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= (a / b * x);
return d;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a, b, x, y;
scanf("%d%d", &a, &b);
exgcd(a, b, x, y);
printf("%d %d\n", x, y);
}
return 0;
}
线性同余方程:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int exgcd(int a, int b, int &x, int &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
else
{
int d = exgcd(b, a % b, y, x);
y -= (a / b * x);
return d;
}
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a, b, x, y, m;
scanf("%d%d%d", &a, &b, &m);
int d = exgcd(a, m, x, y);
if(b % d) puts("impossible");
else cout<<(LL) x * (b / d) % m<<endl;;
}
return 0;
}
中国剩余定理