算术基本定理+容斥定理【知识点】

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的质因数 有哪些,以及质因数有多少个
#include<iostream>
using namespace std;
typedef long long LL;
LL p[30],ge;//数组p存储质因数,ge是质因数的个数 
void getn(LL n){
    ge=0;
    for(LL i=2;i*i<=n;i++)
    {
        if(n%i==0) 
        p[ge++]=i;
        while(n%i==0) 
        n/=i;
    }
    if(n>1) 
    p[ge++]=n;
}
int main()
{
    int a,i; 
    cin>>a;
    getn(a);

    cout<<ge<<endl;
    for(i=0;i<ge;i++)
    {
        cout<<p[i]<<endl;
    }
    return 0;
}

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

/1792/

//因数分解
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=0j=1j=2
i=0(0000)000
i=1(0001)100

i=2(0010)

010
i=3(0011)110
i=4(0100)001
i=5(0101)101
i=6(0110)011
i=7(0111)111

容斥定理部分应用:

  • 对于一个数字来说,区间有多少数字是它的倍数
  • 发现有重叠部分
  • 用容斥定理
  • 假如当前枚举到的状态有两个数字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互质。

     我们可以先求能够被整除的个数,然后一减,就是不可以整除的个数。

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值