题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4135
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.
Input
The first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 1015) and (1 <=N <= 109).
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.
Sample Input
2 1 10 2 3 15 5
Sample Output
Case #1: 5 Case #2: 10
题意: 给定正整数A,B,N,问区间【A,B】中有多少个数与N互素。
题解: 这是一道经典的容斥原理题。
容斥原理公式:
举个简单的例子,比如要求集合AUBUC,则计算公式为AUBUC=A+B+C-AB-AC-BC+ABC。
这道题中,直接求解的话容易想到的是在A-B中遍历判断gcd(N,x)==1是否成立,但这样明显时间复杂度过高。(gcd是最大公因数)
所以可以考虑求问题: 即求【A,B】中多少个数与N不互素。
两个数x,y要不互素,则gcd(x,y)>=2,也就是x和y需要有至少1个公因数gcd存在(1不算)。也就是说,gcd首先得是x的因数,并且y是gcd的整数倍。
所以可以先对N进行质因数分解,比如如果N=30,分解出来是2,3,5.
要求区间【3,15】,令A={x|x的2的整数倍},B={x|x是3的整数倍},C={x|x是5的整数倍},
则【3,15】中与N不互素的数为AUBUC=A+B+C-AB-AC-BC+ABC,
用容斥原理即可求出。
大致步骤先是遍历右边的每一项(先不考虑正负号),
右边由于是ABC组合,把ABC看成二进制即可,比如A就是100,AC是101,ABC就是111,
一个for循环就从1遍历到7(即二进制的111)可遍历到所有项,
每次内循环,就遍历ABC二进制的每一位,同时累加出1的个数来判断正负号。
(求1....n中m的倍数的个数,n / m即可求出)
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
ll A,B,N;
ll factor[2000];// 存储质因数
ll num;// 质因数个数
// 计算1..n之间有多少数与a不互质
ll fun(ll n,ll a) {
if(n == 0) return 0;
num = 0;
// 对a分解质因数
ll temp = a;
for(ll i = 2;i*i <= temp;i++) {
// 找到质因数
if(temp % i == 0) {
factor[num++] = i;
}
while(temp % i == 0) temp /= i;
}
if(temp > 1) {
factor[num++] = temp;
}
// 容斥原理
ll cnt = 0;
bool flag;// 标记正负号
// 在容斥公式中遍历所有数据项,如A+B+C-AB-AC-BC+ABC中遍历每项
for(ll i = 1;i < (ll)(1<<num);i++) {
flag = false;// 负号
ll t = 1;
// 在A,B,C中遍历存在的项
for(ll j = 0;j < num;j++) {
// 判断i的二进制中第j位是否存在
if(i & (ll)(1<<j)) {
t *= factor[j];
if(flag == true)
flag = false;
else
flag = true;
}
}
if(flag) {
cnt += n / t;
} else {
cnt -= n / t;
}
}
return cnt;
}
int main()
{
int Case = 1;
int t;
scanf("%d",&t);
while(t--) {
scanf("%lld%lld%lld",&A,&B,&N);
printf("Case #%d: %lld\n",Case++,(B-A+1) - (fun(B,N)-fun(A-1,N)));
}
return 0;
}