容斥求范围内互质的个数 (njustoj 1922 count_prime)

/*
题目描述: 给定你一个数n,请你统计出在[a,b]这个区间中和n互质的数的个数。
两个数互质当且仅当他们除了1之外没有其他的公共因子或者他们最大的公共因子是1。1和任何数是互素的。
输入: 第一行输入一个整数T(1 <= T <= 100),表示T组测试数据。
接下来T行,每行3个整数a,b,n(1 <= a <=b <=10^15, 1<= n <= 10^9),用空格隔开。
输出: 输出一个整数表示和n互质的数的个数。
样例:
输入 

2


1 10 2
3 10 5
输出 
5
6

*/ 

因为数据范围很大不可能暴力求GCD()==1的情况所以就要用到一些技巧,,,当然算互质的个数不知这一种方法

就是在[a,b]范围内出去n的约数及约数的倍数

#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=1000000;

int p[maxn];

int is_p(ll n)<span style="white-space:pre">			</span>//求因子(不一定是质因子)
{
	int tot=0;
	for(ll i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			p[tot++]=i;
			while(n%i==0) n/=i;
		}
		 
	}
	if(n>1) p[tot++]=n;
	
	return tot;
	
	
}
ll get(ll num,ll n)
{
	ll ans=0;
	for(int i=1;i<(1<<n);i++)<span style="white-space:pre">			</span>//找出互质
	{
		ll temp=1,flag=0;
		for(int j=0;j<n;j++)
		{
			if(i&(1<<j))<span style="white-space:pre">			</span>//运用二进制的规律进行运算
			{
				flag++;
				temp*=p[j];
			}
		}
		if(flag&1) ans+=num/temp;
		else ans-=num/temp;
	}
	return ans;
}
int main()
{

	int t;
	cin>>t;
	while(t--)
	{
		ll a,b,n;
		cin>>a>>b>>n;
		int tot=is_p(n);
		
		cout<<(b-get(b,tot))-(a-1-get(a-1,tot))<<endl;
		 
	}

	
	return 0;
}


posted @ 2016-04-18 13:25  hong-ll  阅读(988)  评论(0编辑  收藏  举报