Description
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a
,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
Input
第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个
正整数,分别为a,b,d。(1<=d<=a,b<=50000)
Output
对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。
Sample Input
2
4 5 2
6 4 3
Sample Output
3
2
HINT
//对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(
6,3),(3,3)。
题解
再不写我就忘了莫反咯…
还好没忘
显然 F [ n ] = ∑ n ∣ d f [ d ] F[n]=\sum_{n|d}f[d] F[n]=∑n∣df[d]
其中F[n]表示约数含有n的数对个数 f表示答案
直接 f [ n ] = ∑ n ∣ d m u [ d n ] F [ d ] f[n]=\sum_{n|d}mu[\frac{d}{n}]F[d] f[n]=∑n∣dmu[nd]F[d]
没忘还是很开心的…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
int mu[51000],pr[51000],plen;
bool v[51000];
void getmu(int MAXN)
{
mu[1]=1;memset(v,true,sizeof(v));
for(int i=2;i<=MAXN;i++)
{
if(v[i])mu[i]=-1,pr[++plen]=i;
for(int j=1;j<=plen&&i*pr[j]<=MAXN;j++)
{
v[i*pr[j]]=false;mu[i*pr[j]]=-mu[i];
if(!(i%pr[j])){mu[i*pr[j]]=0;break;}
}
}
for(int i=1;i<=MAXN;i++)mu[i]+=mu[i-1];
}
int main()
{
getmu(50000);
int T=read();while(T--)
{
int a=read(),b=read(),d=read();a/=d;b/=d;d=1;
LL ans=0;int nxt=0;
for(int i=1;i<=max(a,b);i=nxt+1)
{
if(i>a||i>b)break;
nxt=min(a/(a/i),b/(b/i));
ans+=(LL)(mu[nxt]-mu[i-1])*(a/i)*(b/i);
}
printf("%lld\n",ans);
}
return 0;
}