hdu 2841 题解

题目

题意:就是问在一个$ n* m $的矩阵中站在 $ (0,0) $ 能看到几个整数点。

很明显如果有两个平行向量 $ \vec{a}=(x_1,y_1) $ ,$ \vec{b}=(x_2,y_2) $ 那么很明显 $ (x_1,y_1) ,(x_2,y_2) $ 满足$ x_1=k* x_2 , y_1=k * y_2 $ 。那么两个点最多只能看到一个点,那么我们的目的就是找到有多少个点 $ (x,y) $ 中 $ x,y $ 互质 即 $ gcd(x,y)=1 $

那么我们的问题就转变为 $ (1,n) $ 中有多少个数与 $ (1,m) $ 中的互质,我们假设从 $ (1,n) $ 中选出来一个数 $ i $ 那么我们怎么去判断互质的个数,进行素因子分解,则小于 $ m $ 能被 $ i $ 的素因子整除的数就不是与 $ i $互质的数,这是我们用容斥就可以求出总数。

所以我们只要枚举 $ i $ 即可求出解,容斥怎么样加上有一个质因子的解的个数,减去有两个个质因子解的个数,再加上有三个质因子的解的个数....奇加偶减,就是如果一个数有 $ i $ 个质因数那么我们去判断 $ i $ 的奇偶性,如果是奇数就加上偶数减去,最后用n减去不是 $ i $ 互质的就是最后与 $ i $ 互质的个数了。

代码

#include<bits/stdc++.h>
using namespace std;
int T,n,m,k,prime[40];
long long ans;
int dfs(int n,int m){
	k=0;
	for(int i=2;i*i<=m;++i){
		if(m%i) continue;
		while(m%i==0) m/=i;
		prime[k++]=i;
	}if(m!=1) prime[k++]=m;
	int add=0;
	for(int i=1;i<(1<<k);++i){//分解出来k-1个质数,枚举所有可能的组合情况 2^(k-1)
		int tmp=1,cnt=0;
		for(int j=0;j<k;++j){
			if(!((i>>j)&1)) continue;//没有选这个数
			tmp*=prime[j];
			++cnt;
		}
		if(cnt&1) add+=n/tmp;//奇加偶减
		else add-=n/tmp;
	}
	return n-add;//减去不满足的就是满足的
}
int main(){
	scanf("%d",&T);
	while(T--){
		ans=0;
		scanf("%d %d",&n,&m);
		for(int i=1;i<=n;++i){//固定m枚举i
			ans+=dfs(m,i);
		}printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2019-11-10 11:17  End_donkey  阅读(135)  评论(0编辑  收藏  举报