容斥原理 —— 求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 ;
容斥+dfs求1~n質數個數
n<=100000000 #include<stdio.h> #include<string.h> #include<math.h> int flag[10006]; int num[10000],tota
容斥原理求1到n與k互質個數
參考部落格:傳送門 此處的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~n與x互質的數的個數(6個題、容斥原理)
HDU 4135、POJ 2773、HDU 1695、HDU 2841、ZOJ 2836、HDU 1796 HDU 4135 Co-prime 題意: 求[l,r]與x互質的數的
求1~n中與m互質的數的個數(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++
求N(10^14)以內與N互質的數的和(容斥原理,或者尤拉函式)
#include <iostream> #include <cstring> #include <algorithm> #include <cmath>
bzoj2301 [HAOI2011]Problem b(求gcd==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