1.算数基本定理
1.1定义
算术基本定理(The fundamental theorem of arithmetic) 即唯一分解定理, 告诉我们每一个大于1 的整数若不是质数都可以写成有限多个质因子的乘积且经过适当排序其写法唯一。
1.2应用
1.2.1求解数n的因子个数:
根据算术基本定理:N = p1^r1*p2^r2*p3^r3*...*pn^rn
设n%a==0,即a是n的因子之一;
也有a = p1^a1*p2^a2*p3^a3*...*pn^an
那么 0<=a1<=r1;
所以因子个数 ans=(1 + r1) *(1 + r2) * (1 + r3) * ... * (1 + rn)
//求a的质因数 有哪些,以及质因数有多少个 cout<<ge<<endl; |
1.2.2.求数N的所有因子之和:
要求N的各因子之和
N = p1^r1*p2^r2*p3^r3*...*pn^rn
f(n)是积性函数,即f(a*b)=f(a)*f(b) a,b为素数;
设 f(n) = (p^(r+1) - 1) / (p - 1)
1.2.3,在算术基本定理下看 GCD和LCM:
分解质因数习题 http://codevs.cn/problem
//因数分解
int prm[N],sz;// prm提前预处理 ,prm[0]=2,prm[1]=3,prm[2]=5
map<int, int> f(int n){
map<int, int> ans;
for(int i = 0; i < sz && prm[i] * prm[i] <= n; i++){
while(n % prm[i] == 0){
ans[prm[i]]++;
n /= prm[i];
}
}
if(n != 1) ans[n] = 1;
return ans;
}
prm[N]为预打表处理,把需要范围内的素数打表。代码复杂度sqrt(n).
2.容斥定理
要计算几个集合并集的大小,我们要先将所有单个集合的大
小计算出来,然后减去所有两个集合相交的部分,再加回所
有三个集合相交的部分,再减去所有四个集合相交的部分,
依此类推,一直计算到所有集合相交的部分
若要求 AUBUC的面积 即 A+B+C-A∩B-A∩C-B∩C-A∩B∩C
二进制状态枚举
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n = 3;
for(int i = 0; i < (1 << n); i++){ // 相当于枚举从0~2^n-1个状态的情况
for(int j = 0; j < n ;j++){ //每个状态下的情况,遍历二进制的每一位
printf("%d ", (i >> j )& 1);
}
puts("");//换行
}
return 0;
}
运行结果
0 0 0
1 0 0
0 1 0
1 1 0
0 0 1
1 0 1
0 1 1
1 1 1
j=0 | j=1 | j=2 | |
i=0(0000) | 0 | 0 | 0 |
i=1(0001) | 1 | 0 | 0 |
i=2(0010) | 0 | 1 | 0 |
i=3(0011) | 1 | 1 | 0 |
i=4(0100) | 0 | 0 | 1 |
i=5(0101) | 1 | 0 | 1 |
i=6(0110) | 0 | 1 | 1 |
i=7(0111) | 1 | 1 | 1 |
容斥定理部分应用:
- 对于一个数字来说,区间有多少数字是它的倍数
- 发现有重叠部分
- 用容斥定理
- 假如当前枚举到的状态有两个数字a和b,那么区间中有多少
- 个数字即是a的倍数也是b的倍数呢?
//魔镜题解
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b){
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b){
return a / gcd(a, b) * b;
}
int a[N];
int main(){
int n, m,tmp,ans;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) scanf("%d", &a[i]);
ll ans = 0;
for(int i = 1; i < (1 << m); i++){ // 相当于枚举所有的情况 o(2^n*n)
int cnt = 0;
ll tmp = 1;
for(int j = 0; j < n ;j++){ // a[j]
if(i >> j & 1) {
cnt ++;
tmp = lcm(tmp, a[j]);
}
}
if(cnt & 1) ans += n / tmp;
else ans -= n / tmp;
}
printf("%lld\n", ans);
return 0;
}
容斥原理 1)求数n的质因数
2) 求[1,n] 区间内和m互质的个数
3 ) 求q区间[1,n]和区间[1,n] 不重复的质数对==》求[1,n]的所有数字的欧拉函数的和
4)给定个数组arr和数n,问这个数组内有多少个数与m互质。
我们可以先求能够被整除的个数,然后一减,就是不可以整除的个数。