您的位置:首页 > 其它

SPOJ 7001 VLATTICE - Visible Lattice Points(莫比乌斯反演)

2016-08-03 12:49 337 查看
Description

求经过坐标(0,0,0)和另外任意一个点(x1,y1,z1)的不同的直线有多少条(0<=x1,y1,z1<=n)

Input

第一行为一整数T表示用例组数,每组用例占一行为一整数n(T<=50,1<=n<=1000000)

Output

对于每组用例,输出经过坐标(0,0,0)和另外任意一个点(x1,y1,z1)的不同的直线有多少条

Sample Input

3

1

2

5

Sample Output

7

19

175

Solution

3种情况

1. x1,y1,z1都大于等于1,问题变成求1<=x<=n,1<=y<=n,1<=z<=n,gcd(x,y,z)=1的三元组有多少对

2. x1,y1,z1中有1个为0,问题退化成2维的互质问题了

3. x1,y1,z1中有2个为0,只有三个坐标轴满足

所以答案就是3+3*f(n,n)+g(n,n,n)

其中f(a,b)表示1<=i<=a,1<=j<=b,gcd(i,j)=1的(i,j)对数

g(a,b,c)表示1<=i<=a,1<=j<=b,1<=k<=c,gcd(i,j,k)=1的(i,j,k)对数

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1111111
#define INF 0x3f3f3f3f
typedef long long ll;
bool check[maxn];
int prime[maxn],mu[maxn],sum[maxn];
void Moblus(int n)
{
memset(check,0,sizeof(check));
mu[1]=1;
int tot=0;
for(int i=2;i<=n;i++)
{
if(!check[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0;j<tot;j++)
{
if(i*prime[j]>n)break;
check[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else mu[i*prime[j]]=-mu[i];
}
}
sum[0]=0;
for(int i=1;i<maxn-10;i++)sum[i]=sum[i-1]+mu[i];
}
ll f(int a,int b)
{
if(a>b)swap(a,b);
ll ans=0;
for(int i=1,next=0;i<=a;i=next+1)
{
next=min(a/(a/i),b/(b/i));
ans+=1ll*(a/i)*(b/i)*(sum[next]-sum[i-1]);
}
return ans;
}
ll g(int a,int b,int c)
{
if(a>b)swap(a,b);
if(a>c)swap(a,c);
ll ans=0;
for(int i=1,next=0;i<=a;i=next+1)
{
next=min(a/(a/i),min(b/(b/i),c/(c/i)));
ans+=1ll*(a/i)*(b/i)*(c/i)*(sum[next]-sum[i-1]);
}
return ans;
}
int main()
{
Moblus(maxn-10);
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
ll ans=3+3*f(n,n)+g(n,n,n);
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: