您的位置:首页 > 其它

[bzoj 1101--Poi2007]Zap

2017-11-26 16:06 435 查看
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。

莫比乌斯反演的处女题。其实还是较水的,首先先把a%d,b%d,这样问题便简化成求gcd(x,y)=1的对数了。f(i)表示的是gcd(x,y)=i的对数,F(i)表示的是gcd(x,y)%i=0的对数,那问题又简化成求f(1)。

熟悉莫比乌斯的同学明白在知道f与F的含义后,这题便可做了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int pr=0,prime[51000];
bool v[51000];
long long Mu[51000],sM[51000];
void get_Mu()
{
memset(v,true,sizeof(v));
Mu[1]=sM[1]=1;
for(int i=2;i<=50000;i++)
{
if(v[i]==true)
{
prime[++pr]=i;
Mu[i]=-1;
}
for(int j=1;(j<=pr && i*prime[j]<=50000);j++)
{
v[i*prime[j]]=false;
if(i%prime[j]==0)
{
Mu[i*prime[j]]=0;
break;
}
Mu[i*prime[j]]=-Mu[i];
}
sM[i]=sM[i-1]+Mu[i];
}
}
long long find(int x,int y)
{
if(x>y)swap(x,y);
int last=0;long long s=0;
for(int i=1;i<=x;i=last+1)
{
last=min(x/(x/i),y/(y/i));
s+=(sM[last]-sM[i-1])*(x/i)*(y/i);
}
return s;
}
int main()
{
get_Mu();
int t;
scanf("%d",&t);
while(t--)
{
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
if(d==0)
{
printf("0\n");
continue;
}
long long ans=0;
ans=find(a/d,b/d);
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息