[bzoj1101][莫比乌斯反演]Zap

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82883292

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的数对个数 f表示答案
直接 f [ n ] = n d m u [ d n ] F [ d ] f[n]=\sum_{n|d}mu[\frac{d}{n}]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;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82883292