求a~b中与n互质的数的个数

https://cn.vjudge.net/contest/243561#problem/F

首先我们要会求1~m中与n不互质的数的个数。然后用b-(a-1)-(solve(b)-solve(a-1))即可。solve(b)是指1~b中与n不互质的数的个数。不互质就说明有公共的质因子。

那么solve(b)怎么求呢?先把n的质因子全都筛出来存在一个vector数组里,然后用容斥原理求即可。

因为如果单把有和n的质因子相同的质因子的数算上的话,会有许多重复计算(比如一个数的质因子有3的同时也可能有5),因此我们把有奇数个相同质因子的算作正项,偶数个质因子的算作负项(容斥原理)。比如在1~a中有x个数是3的倍数,y个数是5的倍数,z个数同时是3和5的倍数,那么x和y就加上,z就减去。

怎么枚举质因子的集合呢?我们用二进制来表示一个状态,这个状态代表了n中的某些质因子的组合。如果质因子的个数是奇数的话就作为正项,否则就是负项。用t表示这些质因子的乘积,1~b中有b/t个数是t的倍数。

#include <iostream>
using namespace std;

int num, y[1000000];
__int64 a,b,n;

void run(int x)            //分解质因子 
{
	num=0;
	for (int i=2; i*i<=x; i++)
	{
		if (x % i==0)
		{
			y[num++]=i;
			while (x % i==0)
				x=x/i;
		}
	}
	if (x>1)
		y[num++]=x;
}

int solve(__int64 x)
{
	int p;
	__int64 t,ans=0; 
	for (__int64 i=1; i<(__int64)(1<<num); i++)        //枚举状态 
	{
		t=1;
		p=0;
		for (int j=0; j<num; j++)        //判断第j个质因子 
		{
			if ((__int64)(1 << j) & i) 
			{
				p++;
				t*=y[j];               //质因子 
			}
		}
		
		if (p & 1 ) ans+=x / t;
		else ans-=x / t;
	}
	
	return ans;
	
}

int main()
{	
	int t;
	
	scanf("%d", &t );
	for (int u=1; u<=t; u++)
	{
		scanf("%I64d %I64d %I64d", &a, &b, &n);
		
		run(n);       //筛出来n的质因子,保存在y数组中
		
		printf("Case #%d: ", u);
		printf("%I64d\n", b-(a-1)-(solve(b)-solve(a-1)));	
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41703679/article/details/81489307