大佬博客
hdu 1695
题意:让求从a~b区间和c~d区间有多少对的数的gcd为k,不能有重复的,gcd(2,3)和gcd(3,2)算重复的。
莫比乌斯函数应用的经典题,先求出所有的值然后再减去重复区间的值就好了。
假设F(n)的值为gcd(x,y)==n(a<=x<=b,c<=y<=d)的有多少种。
G(n)代表n|gcd(x,y),(a<=x<=b,c<=y<=d)的有多少种。
由莫比乌斯反演得F(n)=sigma(u(d/n)*G(d)),(n|d),sigma为求和的意思。
由题意可知G(n)==(b/n-(a-1)/n)*(d/n-(c-1)/n)。
求F(k)即可,记得要减去重复的。
这里有有关莫比乌斯函数筛法的求解过程
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+10;
const LL mod=1e9+7;
int p[maxn],mu[maxn];
bool vis[maxn];
void mobius()//求莫比乌斯函数
{
int cont=0;
mu[1]=1;
for(int i=2; i<maxn; i++)
{
if(!vis[i])
{
mu[i]=-1;
p[cont++]=i;
}
for(int j=0; j<cont&&p[j]*i<maxn; j++)
{
vis[p[j]*i]=true;
if(i%p[j]==0)
{
mu[p[j]*i]=0;
break;
}
else
mu[p[j]*i]=-mu[i];
}
}
}
int main()
{
mobius();
int ncase,Z=0;
scanf("%d",&ncase);
while(ncase--)
{
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==0)
{
printf("Case %d: 0\n",++Z);
continue;
}
LL ans=0;
int n=(b,d);
for(int i=k; i<=n; i+=k)//算出所有的情况
ans+=1ll*mu[i/k]*(b/i-(a-1)/i)*(d/i-(c-1)/i);
LL ans2=0;
int l=max(a,c),r=min(b,d);//求出相交区间
if(l<=r)
for(int i=k; i<=r; i+=k)//算出相交区间
ans2+=1ll*mu[i/k]*(r/i-(l-1)/i)*(r/i-(l-1)/i);
ans-=ans2/2;//因为相交区间的也算的是重复点的所以要除2
printf("Case %d: %lld\n",++Z,ans);
}
}