暑假训练6之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 (xy) 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

首先,题目主要是求从0,0能看到的点的个数。

先考虑只有1×1的时候,三个点,根据图明显看出,只需要计算下三角,结果=下三角的个数×2再加1(斜率为1的点)。

那么我们只需要计算斜率从0到1之间的个数就行了,不包括1,包括0.结果设为sum,那么最终就是2*sum+1.

1×1只有一个斜率为0的

2×2斜率有0,1/2(0已经算过了,以后不再算了),其实就多了一个斜率为1/2的。

3×3的时候,有1/3,2/3两个,比以前多了2个

4×4的时候,有1/4,2/4(1/2已经有过了),3/4,所以也是2个

5×5的时候,有1/5,2/5,3/5,4/5,之前都没有,所以多了4个

6×6得到时候,有1/6,2/6(1/3已经有了),3/6(1/2已经有了),4/6(2/3已经有了),5/6,所以只剩2个。

从上面可以发现一个规律,对于n×n,可以从0,0连接到(n,0)到(n,n)上,斜率将会是1/n,2/n......(n-1)/n;

凡是分子和分母能够约分的,也就是有公约数,前面都已经有过了。所以每次添加的个数就是分子和分母互质的个数。

那么问题就转换为,对于一个数n,求小于n的于n互质的数的个数,这不就是欧拉函数么?

//题意:从原点看第一象限里的所有点,能直接看到的点的数目是多少(不包含原点)
//经过一系列的找规律发现:最后就是欧拉函数的相关问题 

#include<bits/stdc++.h>
using namespace std;
int p[10005],phi[10005],k=1;
bool vis[10005];
int main()
{
    int n,T;//vis[i]=false为素数
    vis[1]=true;//1 不是素数
    phi[1]=1;//1的欧拉函数值为1
    for(int i=2;i<=1005;i++)
    {
        if(!vis[i])//若是素数
        {
            p[k++]=i;
            phi[i]=i-1;//素数的欧拉函数值为i-1
        }
        for(int j=1;j<=k&&i*p[j]<=1005;j++)
        {
            vis[i*p[j]]=true;//不是素数
            if(i%p[j]==0)
            {
                phi[i*p[j]]=phi[i]*p[j];//定理
                break;
            }
            else
                phi[i*p[j]]=phi[i]*(p[j]-1);
        }
    }
    cin>>T;
    for(int j=1;j<=T;j++)
    {
        cin>>n;
        int ans=0;
        for(int i=1;i<=n;i++)
            ans+=phi[i];
        printf("%d %d %d\n",j,n,ans*2+1);
    }
    return 0;
}
 

猜你喜欢

转载自blog.csdn.net/lanshan1111/article/details/81346408