1. 程式人生 > >容斥求範圍內互質的個數 (njustoj 1922 count_prime)

容斥求範圍內互質的個數 (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;
}