题目链接:https://www.acwing.com/problem/content/217/
通过容斥原理可以先算是1的倍数的所有数,然后将2,3,5,7倍数的数删掉,其中是2的倍数又是3的倍数的删了两次,所以要加回来,这时候可以发现,系数与莫比乌斯函数是对应的。只算是单个质因子的倍数的数,所以跟莫比乌斯函数有联系。求[a/x]*[b/x]时可以利用性质,将[1,min(a,b)]这段分成不超过O(sqrt(a)+sqrt(b))的小段,对每段求相应的莫比乌斯函数的和,所以可以预处理出莫比乌斯函数的前缀和。
代码:
#include<iostream> #include<cstdio> using namespace std; const int maxn = 50010; int miu[maxn]; bool vis[maxn]; void get_miu(int n){//求莫比乌斯函数的前缀和 for(int i=1;i<=n;i++){ miu[i]=1; vis[i]=0; } for(int i=2;i<=n;i++){ if(vis[i])continue; miu[i]=-1;//质数 for(int j=2*i;j<=n;j+=i){ vis[j]=1; if((j/i)%i==0)miu[j]=0;//分解质因数之后不是单个的 else miu[j]*=-1;//多增加了一个质因数项 } } for(int i=1;i<=n;i++)miu[i]+=miu[i-1]; } void Zap(){ int a,b,k; scanf("%d%d%d",&a,&b,&k); a/=k; b/=k; int ans=0; if(a>b)swap(a,b); for(int x=1,gx;x<=a;x=gx+1){ gx=min(a/(a/x),b/(b/x)); ans+=(miu[gx]-miu[x-1])*(a/x)*(b/x); } printf("%d ",ans); } int main(){ get_miu(50005); int n; cin>>n; while(n--)Zap(); return 0; }