第一道莫比乌斯反演的题目
http://blog.youkuaiyun.com/lixuepeng_001/article/details/50577932
题意:求gcd(x,y)=k,(1<=x<=b,1<=y<=d) 的x,y的对数。
首先就是求gcd(x/k,y/k)=1 的对数,也就是在(1<=x<=b/k,1<=y<=d/k)中x和y互质的对数。
设
F[n]表示gcd(x,y)=n 的倍数的对数
f[n]表示gcd(x,y)=n的对数
然后用这个公式
代表d是n的倍数
因为F[n]=b/n*d/n;
然后f[1]=miu[1]*F[1]+miu[2]*F[2]….一直到min(b,d)
因为题目中说了会有重复的,然后我们减去在[1,b]中一半
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 1e6+6;
#define LL long long
bool vis[maxn];
int primes[maxn];
LL miu[maxn];
void mobius(int limit)
{
memset(vis,0,sizeof(vis));
memset(miu,0,sizeof(miu));
int tot=0;
miu[1]=1;
for(int i=2;i<=limit;i++)
{
if(!vis[i])
{
primes[tot++]=i;
miu[i]=-1;
}
for(int j=0;j<tot;j++)
{
int k=i*primes[j];
if(k>limit) break;
vis[k]=true;
if(i%primes[j]) {
miu[k]=-miu[i];
}
else break;
}
}
}
int main()
{
mobius(maxn);
int t;
scanf("%d",&t);
int case1=0;
while(t--)
{
LL a,b,c,d,k;
scanf("%I64d %I64d %I64d %I64d %I64d",&a,&b,&c,&d,&k);
LL ans=0,ans1=0;
if(k!=0){
b=b/k,d=d/k;
if(b>d) swap(b,d);
for(int i=1;i<=b;i++)
ans+=(b/i)*(d/i)*miu[i];//这里一定要打括号,比如5/2*5/2;
for(int i=1;i<=b;i++)
ans1+=(b/i)*(b/i)*miu[i];
}
printf("Case %d: ",++case1);
ans=ans-ans1/2;
printf("%I64d\n",ans);
}
return 0;
}
据说还可以用容斥原理来做
本文介绍了一道关于莫比乌斯反演的问题,详细解释了如何通过数学方法求解最大公约数等于特定值的整数对的数量,并提供了完整的C++代码实现。
384

被折叠的 条评论
为什么被折叠?



