#莫比乌斯反演#ZOJ 3435 Ideal Puzzle Bobble SP7001 VLATTICE

ZOJ 3435 Ideal Puzzle Bobble

SP7001 VLATTICE - Visible Lattice Points(洛谷题目传送门)

SP7001 VLATTICE - Visible Lattice Points(SPOJ)


题目

问从\((1,1,1)\)能看到\((1\sim L,1\sim W,1\sim H)\)中的多少个点
SP7001 VLATTICE保证\(L=W=H\),且是从\((0,0,0)\)开始看\((0\sim L,0\sim W,0\sim H)\)


分析

将坐标平移到\((0,0,0)\)可以转换成同样的问题,那这题就是就转换成三个平面和一个立体再加上三个坐标轴,
平面就是仪仗队,立体可以用同样的方法推式子,
最后答案就是

\[ans=3+ans_2(L,W)+ans_2(L,H)+ans_2(W,H)+ans_3(L,W,H) \]

时间复杂度\(O(T\sqrt L)\)


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef long long lll;
const int N=1000000; bool v[N|31];
int mu[N|31],prime[N|31],Cnt,A,B,C,mn;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed min(int a,int b){return a<b?a:b;}
inline lll Two(int n,int m){
	rr int MN=min(n,m); rr lll ans=0;
	for (rr int l=1,r,z1,z2;l<=MN;l=r+1){
		z1=n/l,z2=m/l,r=min(n/z1,m/z2);
		ans+=1ll*(mu[r]-mu[l-1])*z1*z2;
	}
	return ans;
}
signed main(){
	mu[1]=1;
	for (rr int i=2;i<=N;++i){
		if (!v[i]) prime[++Cnt]=i,mu[i]=-1;
		for (rr int j=1;j<=Cnt&&prime[j]<=N/i;++j){
			v[i*prime[j]]=1;
			if (i%prime[j]==0) break;
			mu[i*prime[j]]=-mu[i];
		}
	}
	for (rr int i=2;i<=N;++i) mu[i]+=mu[i-1];
	for (rr lll ans;scanf("%d%d%d",&A,&B,&C)==3;){
		--A,--B,--C,mn=min(min(A,B),C);
		ans=3+Two(A,B)+Two(A,C)+Two(B,C);
		for (rr int l=1,r,zA,zB,zC;l<=mn;l=r+1){
			zA=A/l,zB=B/l,zC=C/l,r=min(min(A/zA,B/zB),C/zC);
			ans+=1ll*(mu[r]-mu[l-1])*zA*zB*zC;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2020-10-25 15:26  lemondinosaur  阅读(55)  评论(0编辑  收藏  举报