1. 程式人生 > >算術基本定理+容斥定理【知識點】

算術基本定理+容斥定理【知識點】

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:

//因數分解
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互質。

     我們可以先求能夠被整除的個數,然後一減,就是不可以整除的個數。

這裡寫圖片描述