hdu 2841 题解

Posted donkey2603089141

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",ans);
    }
    return 0;
}

以上是关于hdu 2841 题解的主要内容,如果未能解决你的问题,请参考以下文章

Visible Trees HDU - 2841(容斥)

Visible Trees HDU - 2841(容斥)

- Visible Trees HDU - 2841 容斥原理

- Visible Trees HDU - 2841 容斥原理

HDU2841 Visible Trees(容斥原理)

hdu 2841 Visible Trees(容斥)