【BZOJ2820】GCD

題目

鏈接:BZOJ2820
(權限題,洛谷P2257

解法:莫比烏斯反演

一道較簡單的莫比烏斯反演,推推式子就OK了。

Ans=i=1nj=1mp[gcd(i,j)=p]=pinpjmp[gcd(i,j)=1]=pinpjmpd|gcd(i,j)μ(d)=pd=1min(np,mp)μ(d)indpjmdp1=pd=1min(np,mp)ndpmdpμ(d)

單次詢問時間複雜度:O(π(n)min(n,m)) ,一眼看過去,誒,能過,突然就看到了多組數據T105 。。涼了呀

發現式中有迭代變量的乘積,於是設t=dp ,就有:

Ans=pd=1min(np,mp)ndpmdpμ(d)=t=dpntmtpμ(tp)

在篩出素數後,迭代求出pμ(tp) 的前綴和,
即可使用分塊求解。

時間複雜度:O(T(π(n)logπ(n)+n))

AC代碼

#include<iostream>
#include<cstdio>
#include<vector>

using namespace std;

const int N=10000000;
vector<int> prime;
bool check[10000001];
int T,n,m;
long long summu[10000001],mu[10000001];

void sieve(){
    mu[1]=1ll;
    for(int i=2;i<=N;++i){
        if(!check[i])prime.push_back(i),mu[i]=-1ll;
        for(int j:prime){
            if(i*j>N)break;
            mu[i*j]=-mu[i],check[i*j]=true;
            if(i%j==0){mu[i*j]=0;break;}
        }
    }
    for(int i:prime)for(int j=1;i*j<=N;++j)summu[i*j]+=mu[j];
    for(int i=1;i<=N;++i)summu[i]+=summu[i-1];
}

void solve(int n,int m){
    if(n>m)swap(n,m);
    int lst;long long res=0ll;
    for(int i=1;i<=n;i=lst+1)lst=min(n/(n/i),m/(m/i)),res+=(summu[lst]-summu[i-1])*(n/i)*(m/i);
    printf("%lld\n",res);
}

int main(){
    sieve();
    scanf("%d",&T);for(int i=1;i<=T;++i)scanf("%d%d",&n,&m),solve(n,m);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章