NJUST 1922

count_prime

Time Limit: 1000ms

Memory Limit: 65536KB


Description

给定你一个数n,请你统计出在[a,b]这个区间中和n互质的数的个数。两个数互质当且仅当他们除了1之外没有其他的公共因子或者他们最大的公共因子是1。1和任何数是互素的。

Input

第一行输入一个整数T(1 <= T <= 100),表示T组测试数据。接下来T行,每行3个整数a,b,n(1 <= a <=b <=10^15, 1<= n <= 10^9),用空格隔开。

Output

输出一个整数表示 和n互质 的数的个数。

Sample Input

2
1 10 2
3 10 5

Sample Output

5
6




 搞了一个多小时,终于弄懂了QAQ,容斥原理。

1-i中,是a的倍数和b的倍数的个数为i/a+i/b-i/(a*b)。
设有n个因子,求 1-i中这n个因子的倍数的个数。
定义变量k,从1开始,for到n,每for一次,任取k个因子相乘,如果是奇数个因子,就把当前值加上i/(k个因子的积),否则减去。


dfs 

cur代表当前的因子,now代表当前的乘积,neg代表奇或偶,mid代表i,res代表结果
f代表元素个数,fac代表因子数组0-(f-1)

void dfs(ll cur,ll now,bool neg,ll mid,ll &res){
	if(cur>=f)return;
	ll num=now*fac[cur];
	dfs(cur+1,now,neg,mid,res);//搜不放这个因子的积
	if(neg)res=res+mid/num;
	else res=res-mid/num;
	dfs(cur+1,num,!neg,mid,res);//搜放这个因子的积
} 

#include<iostream>
#include<stdio.h>
using namespace std;
typedef long long ll;
ll t,n,a,b,i,x,flag,sum,fac[105],f;
void dfs(ll cur,ll now,bool neg,ll mid,ll &res){
	if(cur>=f)return;
	ll num=now*fac[cur];
	dfs(cur+1,now,neg,mid,res);
	if(neg)res=res+mid/num;
	else res=res-mid/num;
	dfs(cur+1,num,!neg,mid,res);
}
int main(){
	cin>>t;
	while(t--){
		cin>>a>>b>>n;
		f=0;
		ll so=0;
		for(i=2;n!=1;i++){
			while(n%i==0){
				if(so!=i){
					fac[f++]=i;
				}
				so=i;
				n/=i;
			}
		}
		ll res=0;
		dfs(0,1,1,a-1,res);
		ll so1=a-1-res;
		res=0;
		dfs(0,1,1,b,res);
		ll so2=b-res;
		cout<<so2-so1<<endl;
	}
	return 0;
}


你可能感兴趣的:(NJUST 1922)