第二次做这题,求前缀和的时候还是卡住了
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*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<<' '; } }