1. 程式人生 > >【POJ 3090】Visible Lattice Points

【POJ 3090】Visible Lattice Points

【題目】

傳送門

Description

A lattice point (xy) in the first quadrant (x and y are integers greater than or equal to 0), other than the origin, is visible from the origin if the line from (0, 0) to (xy) does not pass through any other lattice point. For example, the point (4, 2) is not visible since the line from the origin passes through (2, 1). The figure below shows the points (x
y) with 0 ≤ xy ≤ 5 with lines from the origin to the visible points.

Write a program which, given a value for the size, N, computes the number of visible points (xy) with 0 ≤ xy ≤ N.

Input

The first line of input contains a single integer C (1 ≤ C ≤ 1000) which is the number of datasets that follow.
Each dataset consists of a single line of input containing a single integer N
 (1 ≤ N ≤ 1000), which is the size.

Output

For each dataset, there is to be one line of output consisting of: the dataset number starting at 1, a single space, the size, a single space and the number of visible points for that size.

Sample Input

4
2
4
5
231

Sample Output

1 2 5
2 4 13
3 5 21
4 231 32549

【分析】

首先我們要知道一個東西,就是點 (x,y) 會擋住後面所有的 (gx,gy) (g 是大於 1 的整數)

也就是說,如果一個點會被擋住,那麼它的 x,y 就必然有一個大於 1 的公因數

那麼對於所有的點 (x,y) ,如果 x 和 y 互質,那麼它就可以被看見

現在對於這道題來說,直接列舉 x 和 y 的話顯然會超時,我們可以只列舉 x,然後找與 x 互質的 y 的個數,於是我們想到尤拉函式,尤拉函式 phi(n) 就表示 1~n 中與 n 互質的數的個數,所以我們先預處理篩出尤拉函式,直接統計答案即可

最終答案:

answer=2\cdot \sum ^{n}_{i=1}\phi(i)+3

其中 3 代表了(1,1),(0,1),(1,0)這三個點

還是簡單說一下線性篩尤拉函式,這個東西主要是運用了尤拉函式的三個性質:

  1. 如果 i 是質數,那麼 phi[ i ] = i - 1
  2. 如果 a mod b == 0 並且 b 是質數,那麼 phi[ a * b ] = phi[ a ] * b
  3. 如果 a mod b != 0 並且 b 是質數(也就是說a,b互質),那麼 phi[ a * b ] = phi[ a ] * phi[ b ]

根據這三個性質篩就可以了

【程式碼】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
using namespace std;
int phi[N],prime[N];
bool mark[N];
void init()
{
	int i,j,sum=0;
	memset(mark,true,sizeof(mark));
	mark[0]=mark[1]=false;
	for(i=2;i<N;++i)
	{
		if(mark[i])  prime[++sum]=i,phi[i]=i-1;
		for(j=1;j<=sum&&i*prime[j]<N;++j)
		{
			mark[i*prime[j]]=false;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else  phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}
int main()
{
	int n,i,j,x,ans;
	scanf("%d",&n);
	init();
	for(i=1;i<=n;++i)
	{
		ans=3;
		scanf("%d",&x);
		for(j=1;j<=x;++j)
		  ans+=2*phi[j];
		printf("%d %d %d\n",i,x,ans);
	}
	return 0;
}