hdu4135 Co-prime (数论+容斥原理)

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

Hint

In the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.

 

 

Source

The Third Lebanese Collegiate Programming Contest

 


这是个好题,觉得有必要记录一下,看了各个大佬的blog,觉得有一篇讲的比较好,看他的才明白的https://blog.csdn.net/wyg1997/article/details/51998119

首先我们想到的肯定是欧拉函,但是面对区间【1,n】与k互质的个数,欧拉函数必须满足k小于等于n,此题明显不行

换个思路,我们求【1,b】中与k互质的个数  减去  【1,a-1】中与k互质的个数

再转化为    我们求【1,b】中与k不互质的个数  和  【1,a-1】中与k不互质的个数

此时,大佬们先将k质因数分解,将所有的质因数因子放到数组p中,

在区间【1,n】中,与k不互质的数必定是k的质因子的倍数,因为与k不互质的数和k的最大公约数肯定不为一

但是这样枚举的话,有可能会重复算,比如区间中的一个数m,既是2的倍数,也是3的倍数,就会多减一次,此时就要加回来

很容易想到容斥原理,加奇数减偶数,这里的奇数偶数是同时满足奇数个集合或偶数个集合的意思

有关容斥原理:https://blog.csdn.net/qq_41431457/article/details/89949613

有了以上的思路,就需要枚举所有的素因子排列,假如有m个素因子,就有2^m种排列,于是大佬们就想到了用二进制

假如k有5个素因子, 面对其中的一种排列10001,就用到了p[1] 和 p[5] (从左往右),

第i位为 ‘1’ 就表示用到了第i个素因子,‘0’表示没有用到,

根据容斥原理,用到奇数个素因子就加上,偶数个就减去

【1,n】区间中的能整除p[1] 的数有 n / p [1]个,这些数肯定与k不互质,

所以枚举素因子排列就可以筛选掉所有与k不互质的数

#include<bits/stdc++.h>
#define lom long long 
using namespace std;
int p[100000],num;
lom a,b,k;
void decomposition(int x)//分解x的质因子 
{
	num=0;
	for(int i=2; i*i<=x; i++)
	if(x%i==0)
	{
		p[num++]=i;
		while(x%i==0) x/=i;
	}
	if(x>1) p[num++]=x;
}
lom slove(lom n)//求1~n中与k互质的个数 
{
	lom ans=0, lim=(lom)1<<num, cnt, temp;
	
	for(lom i=1; i<lim; i++)
	{
		cnt=0, temp=1;
		for(int j=0; j<num; j++)
		if( ((lom)1<<j) & i)//表示第j个素因子被用到 
		{
			temp*=p[j];//累乘
			cnt++;
		}
		
		if(cnt&1) ans+=n/temp;//有n/temp个数 能整除temp 
		else 	  ans-=n/temp;
	}
	
	return n-ans;
}
int main()
{
	int t,cas=0;
	cin>>t;
	while(t--)
	{
		cin>>a>>b>>k;
		decomposition(k);
		printf("Case #%d: %lld\n",++cas,slove(b)-slove(a-1));
	}
	
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值