hdu2841 Visible Trees (Mobius inversion + number theory block)

Title:

Insert picture description here

solution:

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

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

ans = ∑ i = 1 n ∑ j = 1 m [gcd (i, j) = 1] There is an inversion conclusion: [gcd (i, j) = 1] = ∑ d ∣ gcd (i, j) μ (d ) Then: ans = ∑ i = 1 n ∑ j = 1 m ∑ d ∣ gcd (i, j) μ (d) Change the enumeration order, first enumerate d, then: ∑ d = 1 n μ (d ) ∑ d ∣ i, i <= n ∑ d ∣ j, j <= m 1 ∑ i = 1 n μ (d) ⌊ nd ⌋ ⌊ md ⌋ It can be optimized to O (n) ans = \sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=1]\\ There is an inversion conclusion: [gcd(i,j)=1]=\sum_{d |gcd(i,j))\mu(d)\\ Then there is: ans=\sum_{i=1}^n\sum_{j=1}^m\sum_{d|gcd(i,j)} \mu(d)\\ Change the enumeration order, first enumerate d, then: \\ \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\\ hitting a number theory block can be optimized to O(\sqrt n) a n s=i=1nj=1m[gcd(i,j)=1]Exist in the anti- play knot theory:[gcd(i,j)=1]=dgcd(i,j)μ ( d )That it has:a n s=i=1nj=1mdgcd(i,j)μ ( d )More change pieces move forward order ,First gold cite d ,That it has:d=1nμ ( d )di,i<=ndj,j<=m1i=1nμ ( d ) dndmThen play a number of on sub blocks may be to optimization of the O (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;
}

Guess you like

Origin blog.csdn.net/weixin_44178736/article/details/115253202