hdu2841 Visible Trees(莫比乌斯反演+数论分块)

题意:

在这里插入图片描述

解法:

对于点(x,y),如果gcd(x,y)=1,那么这个点就能被看到,
否则这个点一定会被(x/gcd(x,y),y/gcd(x,y))挡住.

那么问题变为计算n*m的矩阵中,有多少个点横纵坐标互质.

a n s = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ] 存 在 反 演 结 论 : [ g c d ( i , j ) = 1 ] = ∑ d ∣ g c d ( i , j ) μ ( d ) 那 么 有 : a n s = ∑ i = 1 n ∑ j = 1 m ∑ d ∣ g c d ( i , j ) μ ( d ) 更 改 枚 举 顺 序 , 先 枚 举 d , 那 么 有 : ∑ d = 1 n μ ( d ) ∑ d ∣ i , i < = n ∑ d ∣ j , j < = m 1 ∑ i = 1 n μ ( d ) ⌊ n d ⌋ ⌊ m d ⌋ 再 打 个 数 论 分 块 可 以 优 化 到 O ( n ) ans=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=1]\\ 存在反演结论:[gcd(i,j)=1]=\sum_{d|gcd(i,j)}\mu(d)\\ 那么有:ans=\sum_{i=1}^n\sum_{j=1}^m\sum_{d|gcd(i,j)}\mu(d)\\ 更改枚举顺序,先枚举d,那么有:\\ \sum_{d=1}^n\mu(d)\sum_{d|i,i<=n}\sum_{d|j,j<=m}1\\ \sum_{i=1}^n\mu(d)\lfloor\frac{n}{d}\rfloor \lfloor\frac{m}{d}\rfloor\\ 再打个数论分块可以优化到O(\sqrt n) ans=i=1nj=1m[gcd(i,j)=1]:[gcd(i,j)=1]=dgcd(i,j)μ(d):ans=i=1nj=1mdgcd(i,j)μ(d),d,:d=1nμ(d)di,i<=ndj,j<=m1i=1nμ(d)dndmO(n )

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxm=1e5+5;
int p[maxm],c;
int np[maxm];
int mu[maxm];
int n,m;
void init(){
    
    
    mu[1]=1;
    for(int i=2;i<maxm;i++){
    
    
        if(!np[i])p[c++]=i,mu[i]=-1;
        for(int j=0;j<c;j++){
    
    
            if(p[j]*i>=maxm)break;
            np[p[j]*i]=1;
            mu[p[j]*i]=i%p[j]?-mu[i]:0;
            if(i%p[j]==0)break;
        }
    }
    for(int i=1;i<maxm;i++){
    
    
        mu[i]+=mu[i-1];
    }
}
void solve(){
    
    
    cin>>n>>m;
    int mi=min(n,m);
    int ans=0;
    for(int l=1,r;l<=mi;l=r+1){
    
    
        r=min(n/(n/l),m/(m/l));
        ans+=(mu[r]-mu[l-1])*(n/l)*(m/l);
    }
    cout<<ans<<endl;
}
signed main(){
    
    
    init();
    int T;cin>>T;
    while(T--){
    
    
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/115253202