给定点(a,b,c)与(1,1,1)确定一个长方体,长方体边上及内部总共有a*b*c个点,问从(1,1,1)总共能看到多少个点
这题是bzoj 2190的升级版,由二维转换到了三维。推荐大家先理解一下bzoj 2190先。
之后大家就会发现其实这两题没变多少,只需将a-1,b-1,c-1,(1,1,1)变成(0,0,0),思路便差不多了。再多讨论几种情况,(i,j,0)、(i,0,k)、(0,j,k),再加上(i,j,k)就行了(0<=i<=a-1,0<=j<=b-1,0<=k<=c-1)。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
long long pr,prime[1100000];
long long Mu[1100000],sM[1100000];
bool v[1100000];
void get_Mu()
{
memset(v,true,sizeof(v));
Mu[1]=1;sM[1]=1;
for(int i=2;i<=1000000;i++)
{
if(v[i]==true)
{
prime[++pr]=i;
Mu[i]=-1;
}
for(int j=1;(j<=pr && i*prime[j]<=1000000);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 find1(int x,int y)
{
if(x>y)swap(x,y);
long long ans=0,last=0;
for(int i=1;i<=x;i=last+1)
{
last=min(x/(x/i),y/(y/i));
ans+=(sM[last]-sM[i-1])*(x/i)*(y/i);
}
return ans;
}
long long find2(int x,int y,int c)
{
if(x>y)swap(x,y);
if(x>c)swap(x,c);
long long ans=0,last=0;
for(int i=1;i<=x;i=last+1)
{
last=min(c/(c/i),min(x/(x/i),y/(y/i)));
ans+=(sM[last]-sM[i-1])*(x/i)*(y/i)*(c/i);
}
return ans;
}
int main()
{
get_Mu();
int a,b,c;
while(scanf("%d%d%d",&a,&b,&c)!=EOF)printf("%lld\n",find1(a-1,b-1)+find1(a-1,c-1)+find1(b-1,c-1)+find2(a-1,b-1,c-1)+3);
return 0;
}