【洛谷P3455】ZAP-Queries

题目大意:求 \[\sum\limits_{i=1}^a\sum\limits_{j=1}^b[gcd(i,j)=c]\]

题解:学会了狄利克雷卷积。
\[\epsilon=\mu \ast 1\]
将艾弗森表达式转化成卷积的形式,在调换求和顺序,消去不必要的和式。最后利用除法分块+预处理的莫比乌斯函数前缀和在 \(O(\sqrt n)\) 时间内单次回答询问。

代码如下

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+10;

int mu[maxn],sum[maxn],prime[maxn],tot;
bool vis[maxn];

void seive(){
    mu[1]=1,vis[1]=1;
    for(int i=2;i<=5e4;i++){
        if(!vis[i])prime[++tot]=i,mu[i]=-1;
        for(int j=1;i*prime[j]<=5e4;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=5e4;i++)sum[i]=sum[i-1]+mu[i];
}

ll calc(ll a,ll b){
    if(a>b)swap(a,b);
    ll ans=0;
    for(int i=1;i<=a;i++){
        int j=min(a/(a/i),b/(b/i));
        ans+=(ll)(sum[j]-sum[i-1])*(ll)(a/i)*(ll)(b/i);
        i=j;
    }
    return ans;
}

int main(){
    seive();
    int T;scanf("%d",&T);
    while(T--){
        int a,b,d;
        scanf("%d%d%d",&a,&b,&d);
        printf("%lld\n",calc(a/d,b/d));
    }   
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wzj-xhjbk/p/10713246.html