文章目錄
1. 題目描述
1.1. Limit
Time Limit: 1000 ms
Memory Limit: 32768 kB
1.2. Problem Description
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-prime
or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.
1.3. Input
The first line on input contains T the number of test cases, each of the next lines contains three integers where and .
1.4. Output
For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.
1.5. Sample Input
2
1 10 2
3 15 5
1.6. Sample Output
Case #1: 5
Case #2: 10
In the first test case, the five integers in range [1,10]
which are relatively prime to 2
are {1,3,5,7,9}
.
1.7. Source
The Third Lebanese Collegiate Programming Contest
2. 解讀
這道題我們需要使用到的是容斥原理。
容斥原理分爲三種實現1:
1.位運算與二進制枚舉(容易理解)
2.隊列數組(耗時最短)
3.遞歸(代碼最短但不容易理解)
在這裏我們主要討論比較好理解的位運算與二進制枚舉方法,其他兩種方法可以參考深海滄瀾夜未央的博客2。
首先分析問題,我們要求的是區間 之內 和 互質的數的個數,考慮道題目中的範圍 ,暴力算法是不太可能了。
而在之前的一篇筆記中,我們提到了用埃氏篩法來求 範圍內的所有質數,主要思想是不斷篩除 中的非質數和它的倍數,直到列表內只剩下質數爲止。也就是說篩除掉一個區間內的非質數是比較高效的。
順着這個思路我們就可以想到,我們可以求出區間 之內和 不互質的數的數量 和 區間 之內和 不互質的數的數量 ,計算 $(B - w_B) - (A - 1- w_{A - 1}) $ 就可以求出答案了。
那麼,我們要怎麼求出 和 呢,不需要一個個去篩除那麼麻煩,只需要求出 的所有質因數 ,形成一個集合 ,把 和 中所有 的倍數的數量求出來並減去就可以了。
如果 集合中只有一個數 ,我們只需要這樣計算就可以了
但很明顯 集合中很可能不僅僅只有一個數,這裏就涉及到容斥原理了。
假設 ,,,那麼計算公式如下
這裏又涉及到容斥原理中一個奇加偶減的規律,也就是在迭代計算的過程中 要加上 除以奇數個質因數相乘所得的結果,減去 除以偶數個質因數相乘所得的結果。
又有問題出現了,我們要怎麼遍歷所有組合的情況呢? 在最開始提到的位運算與二進制枚舉方法閃亮登場。還是假設 ,把 的組合情況 用 3 位二進制來表示
根據排列組合規律, 個數的任意個數的組合共有 種情況。
我們只需要把 從 加到 即可
若 中某一位置 爲 1,則把 取出與其他爲 1 的質因數相乘即可遍歷所有組合情況。
3. 代碼
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
typedef long long ll;
// 存儲質因數
ll prime[100];
// 質因數計數
int cnt;
// 計算質因數
void init(int m)
{
cnt = 0;
for (ll i = 2; i * i < m; i++)
// 若爲因數
if (m % i == 0) {
//prime儲存素因子,cnt爲素因子的個數
prime[cnt++] = i;
// 將這個質因數從m中除去,防止計算到質因數的倍數
while (m % i == 0) {
m /= i;
}
}
//這裏是因爲有的n的因子大於sqrt(n),比如14,他的素因子有2,7
if (m > 1)
prime[cnt++] = m;
}
// 容斥原理計算[2, cur] 中不與 N 互斥的數的數量
ll IE_Principle(ll cur)
{
// 存儲質因數組合的乘積
ll res = 0;
// 存儲結果
ll ans = 0;
// 從 0 遍歷到 2^cnt - 1
for (ll i = 1; i < ll(1 << cnt); i++) {
res = 1;
ll flag = 0;
// 遍歷所有數位
for (ll j = 0; j < cnt; j++) {
//出現因子
if (i & (ll(1 << j))) {
// 統計出現的集合個數
flag++;
// 取並之後的因子乘積
res *= prime[j];
}
}
// 判斷組合中因子個數的奇偶性
if (flag & 1) {
// 若爲奇數 加
ans += cur / res;
} else {
// 若爲偶數 減
ans -= cur / res;
}
}
return ans;
}
int main()
{
// test case
ll t;
cin >> t;
// 計數
int icase = 0;
// 存儲 A B N
ll a, b, n;
// 存儲結果
ll ans;
// 對每一個test case進行遍歷
while (t--) {
// 初始化
memset(prime, 0, sizeof(prime));
// 輸入
cin >> a >> b >> n;
// 求質因數
init(n);
// 使用容斥原理進行計算並輸出
ans = b - IE_Principle(b) - (a - 1 - IE_Principle(a - 1));
printf("Case #%d: %lld\n", ++icase, ans);
}
return 0;
}
代碼參考自深海滄瀾夜未央的博客2,思路借鑑了生如夏花的博客3。
4. 參考文獻
[1] 深海滄瀾夜未央. CSDN博客. 容斥原理(組合數學)總結
[2] 深海滄瀾夜未央. CSDN博客. HDU4135 Co-prime【容斥原理】3方法
[3] 生如夏花. 博客園博客. hdu 4135(容斥原理)
聯繫郵箱:[email protected]
Github:https://github.com/CurrenWong
歡迎轉載/Star/Fork,有問題歡迎通過郵箱交流。