【解题报告】NYOJ471 好多的树 -- 容斥原理

/*
	NYOJ471  好多的树 -- 容斥原理
	求互质数对(0<i<n , 0<j<m)的个数
	打表 f[i]表示有几个素因子,如果存在相同的则为-1(素因子一次不能多除)
	f[1]=0
	f[2]=1
	f[3]=1
	f[4]=-1
	f[5]=1
	f[6]=2
	f[7]=1
	f[8]=-1
	f[9]=-1
	f[10]=2
	然后就是解
	if(f[i]>=0)
		ans += (f[i]&1) ? (-((ll)n/i)*((ll)m/i)) : (((ll)n/i)*((ll)m/i));
			
*/

#pragma comment(linker, "/STACK:102400000,102400000")
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <ctime>
#include <queue>
#include <cmath>
#include <set>
#define CLR(a,v) memset(a,v,sizeof(a))
using namespace std;
typedef long long       ll;
typedef pair<int,int>   pii;

const double PI = acos(-1.0);
const int N = 1e5+10;

ll gcd (int a,int b){
	return b ? gcd(b, a%b) : a ;
}

void TestRand(){
	srand((unsigned int)time(NULL));
	int g = 0 , i = 0;
	for( i = 0 ; i < 500000 ; i++)
		if(gcd( rand()+1,rand()+1 ) == 1){
			g++;
		}
	printf("%lf  %lf\n",g*1.0/i,6.0/(PI*PI));
}



int prime[N];
bool p[N];
int GetPrime(){
	int cnt = 0;
	for(int i = 2 ; i < N ; i++){
		if( !p[i] ){
			prime[cnt++] = i;
			for(int j = i+i ; j < N ; j+=i){
				if(!p[j])
					p[j]=true;
			}
		}
	}
	return cnt;
}

int f[N]; // f[i] i的素因子个数
void Init(int PrimeCnt){
	f[1]=0;
	for(int i = 2 ; i < N; i++){
		if(!p[i]){f[i]=1;continue;} // 如果是素数
		int a = i;
		for(int j = 0 ; j < PrimeCnt ; j++){
			if(a % prime[j] == 0){
				f[i]++;
				a /= prime[j];
			}
			if(a % prime[j] == 0){
				f[i] = -1;
				a /= prime[j];
			}
			if(a < prime[j] || f[i]==-1) break;
		}
	}
}

int main(){
	//freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
	int PrimeCnt = GetPrime();
	Init(PrimeCnt);
	int T;
	scanf("%d",&T);
	while(T--){
		int m,n;
		scanf("%d%d",&m, &n);
		int bound = min(m,n);

		ll ans = 0;
		for(int i = 1 ; i <= bound ; i++){
			if(f[i]>=0){
				ans += (f[i]&1) ? (-((ll)n/i)*((ll)m/i)) : (((ll)n/i)*((ll)m/i));
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

你可能感兴趣的:(【解题报告】NYOJ471 好多的树 -- 容斥原理)