1. 程式人生 > >容斥原理 —— 求1~n有多少個數與k互質(二進位制演算法詳細解釋&模板)

容斥原理 —— 求1~n有多少個數與k互質(二進位制演算法詳細解釋&模板)

這裡有一道經典的例題,可以看一下:點選開啟連結

這裡的n可能要大於k的,所以不能用尤拉函式去做。

我們首先把k分解質因數,儲存到p陣列中,num表示質因子的數量。

void pr(int k)		//求k的質因子
{
	num = 0;
	for (int i = 2 ; i * i <= k ; i++)
	{
		if (k % i == 0)
		{
			p[num++] = i;
			while (k % i == 0)
				k /= i;
		}
	}
	if (k > 1)
		p[num++] = k;
}


然後用容斥原理,我們反著求不與k互質的數的個數,到時候一減就得出結果了。

舉個例子,比如 k 的質因子有 2,3,5。那麼2、3、5的倍數都不和 k 互質,另外還沒有完,可能有重複的地方,比如6,既是2的倍數又是3的倍數,前面用 k/2 + k/3 的時候多減了,這個時候要加上 k / (2*3)。同理,10,15這一類數都應該加上。但是還有類似於30這樣的數,它是2,3,5的倍數,減的時候又多減了。

然後我們會發現,出現奇數個數,就用加法,偶數個數用減法。

最後的式子是這樣的:k / 2 + k / 3 + k / 5 - k / (2 * 3) - k / (3 * 5) - k / (2 * 5) + k / (2 * 3 * 5)

有點長,看一下容易發現我說的奇偶的規律。

但是要怎麼取算這個又出現問題了。

這裡提供二進位制的方法,個人覺得比較好理解。

設質因數的個數為m。

有一個浮動的數字,從1 ~ m依次遞增,它的二進位制的每一位表示用了哪些數字,比如5(101),其二進位制的第一位和第三位(倒著數)是1,則它表示用了第一個質因數和第三個質因數。就是這個意思,這樣就能發現:從1到m遍歷一遍,就把所有的可能都包括了。

寫的挺累的,有錯誤謝謝指正,轉載說明出處。

下面貼上模板程式碼:

__int64 solve(__int64 n)		//1~n中不與k互質的數 
{
	__int64 ans = 0;
	for (__int64 i = 1; i < (__int64)1 << num ; i++)		//其二進位制位為1,表示這些質因數被用到 
	{
		int ant = 0;		//用奇數個質因數加,偶數個減
		__int64 t = 1;
		for (int j = 0 ; j < num ; j++)
		{
			if (((__int64)1 << j) & i)
			{
				t *= p[j];
				ant++;
			}
		}
		if (ant & 1)		//奇數加
			ans += n / t;
		else		//偶數減 
			ans -= n / t;
	}
	return ans;
}



相關推薦

原理 —— 1~n多少個數k二進位制演算法詳細解釋&模板

這裡有一道經典的例題,可以看一下:點選開啟連結 這裡的n可能要大於k的,所以不能用尤拉函式去做。 我們首先把k分解質因數,儲存到p陣列中,num表示質因子的數量。 void pr(int k) //求k的質因子 { num = 0; for (int i = 2 ;

+dfs1~n質數個數

n<=100000000 #include<stdio.h> #include<string.h> #include<math.h> int flag[10006]; int num[10000],tota

原理1nk個數

參考部落格:傳送門 此處的k<=1e9、 #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #include<vecto

LightOJ - 1117 Helping Cicada 1~n多少個數不能被這m個數中任意一個整除(+狀態壓縮)

vol == show fine cst href main http color 題意:http://www.lightoj.com/volume_showproblem.php?problem=1117 考慮1個數k,1~n有[n/k]個數能被k整除,[a]表示a向下取

組合數學-原理-指定區間內n素的數的個數

求指定區間內與n互素的數的個數 給出整數n和r。求區間[1,r]中與n互素的數的個數。 去解決它的逆問題,求不與n互素的數的個數。 考慮n的所有素因子pi(i=1···k) 在[1,r]中有多少數能被pi整除呢?它就是   然而,如果我們單純將所有結果,會得到錯誤答案。有些

原理-區間內n的數】HDOJ Co-prime 4135

Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N. Two integers are said to be co-

hdu4153原理質數

ase class ace ini n) turn sign for http 傳送門 ac代碼: #include<bits/stdc++.h> #define per(i,a,b) for(int i=a;i<=b;i++) usin

hdu 5072 Coprime+快速統計cnt個數x個數

題目連結: 轉換成求滿足條件的反面: ①:a和b,c互質,b和c不互質 ②:a和b,c不互質,b和c互質 於是就是列舉每個數,找出與他互質的個數與不互質的個數 答案就是:互質個數*不互質個數/2 至於為什麼要除2,我看得還不是很懂 然後就變成了:怎樣快速統計

1~nx的數的個數6個題、原理

HDU 4135、POJ 2773、HDU 1695、HDU 2841、ZOJ 2836、HDU 1796 HDU 4135 Co-prime 題意: 求[l,r]與x互質的數的

1~nm的數的個數m>n 附hdu1695題解(尤拉函式+原理)

int calc(int n,int m) { //求1~n 與m互質的數的個數 int num=getFactors(m); //先將m分解質因數 int sum=0; //先求出不互質的個數,最後用n減去該數 for(int state=1;

a~b內n素的數的個數 原理

題意:給定你一個數n,請你統計出在[a,b]這個區間中和n互質的數的個數。兩個數互質當且僅當他們除了1之外沒有其他的公共因子或者他們最大的公共因子是1。1和任何數是互素的。 輸入:第一行輸入一個整

指定區間內n素的數的個數 原理

題意:給定整數n和r,求區間[1, r]中與n互素的數的個數。 如果使用暴力的方法,枚舉1...n,判定gcd(i,n)是否為1的復雜度是log(max(i,n)),總的復雜度就是r∗log(ma

原理解決某個區間[1,n]閉區間m互質數數量問題

除法 als tdi pla cin ack 二分 ans || 首先貼出代碼(閉區間[1,n]範圍內和m互質的數) 代碼: int solve(II n,II m){ vector<II>p; for(II i=2;i*i<=m;i++

N10^14以內N的數的和(原理,或者尤拉函式

#include <iostream> #include <cstring> #include <algorithm> #include <cmath>

bzoj2301 [HAOI2011]Problem bgcd==k個數莫比烏斯反演+原理

首先我們搞掉下界,怎麼搞呢,用容斥原理即可。(看做矩形區間),然後我們需要求∑x=1n∑y=1ngcd(x,y)==k。 ∑x=1⌊n/k⌋∑y=1⌊m/k⌋gcd(x,y)==1 ∑x=1⌊n/k

【bzoj3456】城市規劃 原理+NTT+多項式

方案 所在 scanf 整理 輸入 eof 輸出 std define 題目描述 求出n個點的簡單(無重邊無自環)無向連通圖數目mod 1004535809(479 * 2 ^ 21 + 1). 輸入 僅一行一個整數n(<=130000) 輸出 僅一行一個整

Leetcode 920. Number of Music Playlists 原理(O(N log L))

題意 給你n首不同的歌,有一個L長的播放列表,讓你這用這些歌,在滿足某種條件的前提下,把播放列表填滿,問有多少種填法 兩個條件是:1. 每首歌至少用1次;2. 如果一個歌放在了第i個位置上,則下一次它最早只能出現在i+k+1的位置上 思路 這個題

BZOJ3994:約數個數莫比烏斯反演:[1,N]*[1,M]的矩陣的因子個數

Description  設d(x)為x的約數個數,給定N、M,求   Input 輸入檔案包含多組測試資料。 第一行,一個整數T,表示測試資料的組數。 接下來的T行,每行兩個整數N、M。 Ou

[帶標號無向連通圖計數 原理 多項式逆 多項式ln 模板題] BZOJ 3456 城市規劃

可以通過容斥求出答案的表示式fi=2C2i−∑j=1i−1Cj−1i−1∗fj∗2C2i−j 其中前一部分表示i個點任意連邊 後半部分列舉1所在的連通塊然後容斥掉 ∑j=1ifj(j−1)!∗2C2i−j(i−j)!=2C2i(i−1)! 這是個卷積的

Min_25篩初級應用:$[1,n]$內質數個數

#include <bits/stdc++.h> #define rin(i,a,b) for(int i=(a);i<=(b);++i) #define irin(i,a,b) for(int i=(a);i>=(a);--i) #define trav(i,a) for(int i