P3455 [POI2007]ZAP-Queries(莫比乌斯反演)

思路

和YY的GCD类似但是更加简单了
类似的推一波公式即可

[F(n)=sum_{n|d}f(d) ]

[f(n)=sum_{n|d}mu(frac{d}{n})F(d) ]

[F(d)=lfloorfrac{n}{d} floor imeslfloorfrac{m}{d} floor ]

[f(x)=sum_{x|d}mu(frac{d}{x}) imeslfloorfrac{n}{d} floor imeslfloorfrac{m}{d} floor ]

[f(x)=sum_{t=1}^{lfloorfrac{n}{x} floor}mu(t) imeslfloorfrac{n}{x imes t} floor imeslfloorfrac{m}{x imes t} floor ]

然后整除分块即可

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int T,n,m,mu[51000],iprime[51000],isprime[51000],summu[51000],cnt,k;
void prime(int n){
    isprime[1]=true;
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!isprime[i])
            iprime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&iprime[j]*i<=n;j++){
            isprime[iprime[j]*i]=true;
            mu[iprime[j]*i]=-mu[i];
            if(i%iprime[j]==0){
                mu[iprime[j]*i]=0;
                break;
            }
        }
    }
    for(int i=1;i<=n;i++)
        summu[i]=summu[i-1]+mu[i];
}
long long f(int k){
    long long ans=0;
    for(int l=1,r;l<=min(n,m);l=r+1){
        r=min((n/(n/(l))),(m/(m/(l))));
        ans+=1LL*(summu[r]-summu[l-1])*(n/(l*k))*(m/(l*k));
        }
    return ans;
}
int main(){
    prime(50100);
    scanf("%d",&T);
    while(T--){
        scanf("%d %d %d",&n,&m,&k);
        if(n<m)
            swap(n,m);
        printf("%lld
",f(k));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/dreagonm/p/10066914.html