莫比乌斯反演+二维前缀和——hdu4746二刷

第二次做这题,求前缀和的时候还是卡住了

fg函数的反演是可以直接用莫比乌斯基本代换式来代换的

#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
#define ll long long 

bool vis[maxn];
int mu[maxn],prime[maxn],mm,num[maxn];
void init(){//顺便筛出每个数的质因子个数 
    mu[1]=1;num[1]=0;
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            mu[i]=-1;
            prime[++mm]=i;
            num[i]=1;
        }
        for(int j=1;j<=mm;j++){
            if(prime[j]*i>=maxn)break;
            vis[i*prime[j]]=1;
            if(i%prime[j]==0){
                num[i*prime[j]]=num[i]+1;
                mu[i*prime[j]]=0;
                break;
            }
            else {
                mu[i*prime[j]]=-mu[i];
                num[i*prime[j]]=num[i]+1;
            }
        } 
    }
}

long long n,m,p;
int sum[maxn][22];//前缀和,质因子个数,等式值 
void prework(){
    for(int k=1;k<maxn;k++)
        for(int j=1;j*k<maxn;j++)
            sum[j*k][num[k]]+=mu[j];
    
    for(int i=1;i<maxn;i++)
        for(int j=0;j<=20;j++)
            sum[i][j]+=sum[i][j-1];
    for(int i=1;i<maxn;i++)
        for(int j=0;j<=20;j++)
            sum[i][j]+=sum[i-1][j];
}



int main(){
    init();
    prework(); 
    int t;cin>>t;
    while(t--){
        scanf("%lld%lld%lld",&n,&m,&p);
        if(n>m)swap(n,m);
        if(p>=20){
            printf("%lld\n",n*m); 
            continue;
        }
        
        long long ans=0;
        for(int l=1,r;l<=n;l=r+1){
            r=min(n/(n/l),m/(m/l));
            ans+=(sum[r][p]-sum[l-1][p])*(n/l)*(m/l);    
        }    
        cout<<ans<<'\n';
    }    
}

 

posted on 2019-07-06 19:34  zsben  阅读(192)  评论(0编辑  收藏  举报

导航