转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents
题意:
给定整数a,b,c,d,k,a=c=1求 a≤x≤c, b≤y≤d(1≤c,d,k≤105) 且gcd(x,y)=k的数对(x,y)有多少对.
思路:
这个题比bzoj2818 稍微复杂一点,可以看一下这里
由于a,b不相等,不能像bzoj2818一样用欧拉函数来做了
莫比乌斯反演轻松解决
g(n)=∑n|df(d)⟺f(n)=∑n|dμ(dn)g(d)
设 f(n) 代表 gcd(x,y)=n 的(x,y)的对数
设 g(n)代表gcd(x,y)%n=0 的(x,y)的对数
这样就有了
g(n)=∑n|df(d)
然后利用反演公式,因为 g(n) 非常的好求, g(n)=cn×dn
根据上述的反演公式直接计算就可以了
还有一点就是这个题要求(x,y)和(y,x)视为相同的,所以需要去重,怎么去呢,其实很简单
我们在算完 a≤x≤c, b≤y≤d ,再算一下 a≤x≤min(c,d), b≤y≤min(c,d) ,然后减一下就行
具体代码如下:
Result:Accepted
Memory: 2268KB
Time : 31MS
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=1e5+5;
bool vis[maxn];
int prime[maxn];
int mu[maxn];
int n,a,b,c,d,k;
int tot;
ll ans1,ans2;
int Case;
void mobius()
{
memset(vis,0,sizeof vis);
mu[1] = 1;
tot = 0;
for(int i = 2; i <maxn; i++)
{
if( !vis[i] ){
prime[tot++] = i;
mu[i] = -1;
}
for(int j = 0; j < tot; j++)
{
if(i * prime[j] >=maxn) break;
vis[i * prime[j]] = true;
if( i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
mu[i * prime[j]] = -mu[i];
}
}
}
int main()
{
ios::sync_with_stdio(false);
mobius();
int T;
cin>>T;
while(T--)
{
ans1 = 0;
ans2 = 0;
cin>>a>>b>>c>>d>>k;
cout<<"Case "<<++Case<<": ";
if(k==0)
{
cout<<0<<endl;
continue;
}
n = min(b,d);
for(int x=k;x<=n;x+=k)
{
ans1+= 1LL*mu[x/k]*(b/x)*(d/x);
ans2+= 1LL*mu[x/k]*(n/x)*(n/x);
}
ans2--;
cout<<ans1-ans2/2<<endl;
}
}