Description
给出一个整数n,表示1,2,...,n。从这n个数中任意选择3个不同的数字x,y,z,问x,y,z的最大公约数等于m的方案有多少种?(注意:(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)属于同一种方案)
Input
第一行输入一个整数T(1 <= T <= 100),表示有T组数据,
接下来T行,每行2个整数n, m(1 <= m <= n <= 10^5)
Output
输出一个整数表示答案
Sample Input
1
5 1
Sample Output
10
gcd为k,那么三个数都是k的倍数;
把倍数容斥掉就好了;
用莫比乌斯反演一下。
#include <iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
int mu[100005],vis[100005],prime[100005];
int N=100000,cnt;
void Init()
{
memset(vis,0,sizeof(vis));
mu[1] = 1;
cnt = 0;
for(int i=2; i<N; i++)
{
if(!vis[i])
{
prime[cnt++] = i;
mu[i] = -1;
}
for(int j=0; j<cnt&&i*prime[j]<N; j++)
{
vis[i*prime[j]] = 1;
if(i%prime[j]) mu[i*prime[j]] = -mu[i];
else
{
mu[i*prime[j]] = 0;
break;
}
}
}
}
ll c(int n)
{
if(n<=2)
return 0;
ll res=n;
res*=(n-1);
res/=2;
res*=(n-2);
res/=3;
return res;
}
int main()
{
int T;
scanf("%d",&T);
Init();
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
n/=m;
ll ans=0;
for(int i=1;i<=n;i++)
ans+=mu[i]*c(n/i);
cout<<ans<<endl;
/* for(int i=1;i<=100;i++)
cout<<mu[i]<<" ";*/
}
return 0;
}