POJ 3090 visible lattice points(可见的格点)(欧拉函数)

我们来看一下题面:

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.

translation:一个在第一象限内的格点(x,y),除了原点之外,如果连接原点和该格点(x,y)的线段没有经过任何其他的格点,那么称之为可见。比如说,点(4,2)不可见,因为原点和它的连线经过了(2,1)这个点。下边(上边)的图像展示了第一象限内(x,y<=5)的格点可见情况。

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

translation:写一个程序,对于给定的大小值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.

translation:第一行包含一个整数C,这代表接下来的数据组数。每一组数据中都只在一行内输入一个整数:N,这代表的正方形区域的边长。

Output

扫描二维码关注公众号,回复: 5633432 查看本文章

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.

translation:对于每组测试数据,仅需输出一行:数据组数,空格,正方形区域边长长度(N),空格,可见点数。

Sample Input

4
2
4
5
231

Sample Output

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

我们仔细分析一下题意,发现了如下关键题眼:经过(0,0)和(x,y)的一条直线不再经过其他格点,而格点都是整数坐标构成的点。这也就是说,y=kx这个方程不能通过\frac{y}{n}=\frac{x}{n}这种方式得到其他适合的整数解,所以x,y必互质。

然而用辗转相除法做1000*1000*1000次显然会超时,所以这个时候就会想到欧拉函数:计算[1,n)内互质数的个数的一个函数。对0到n的每个数的欧拉函数值进行求和,再乘2(因为是二维),同时我们还得注意一下特殊情况(0,0) (1,0) (0,1)这三个点(0没有互质数,因而没有欧拉函数值),要在最后加上他们。

下面是实现代码

#include <iostream>
#include <cstdio>
//#include <bits/stdc++.h>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <cmath>
//#include <minmax.h>
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define reset(a,b) memset(a,b,sizeof(a))
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
/*you can feel the pulse of your destiny...
The nervous feeling fills you with determination.*/
int primess[5000],cnt=0,eulers[5000];
bool vis[10006];
void primes()//欧拉筛求欧拉函数值&质数表
{
   for(int i=2;i<=1004;i++)
   {
      if(vis[i]==0)
      {
         primess[cnt++]=i;
         eulers[i]=i-1;
      }
      for(int j=0;j<cnt&&i*primess[j]<=1004;j++)
      {
         vis[i*primess[j]]=1;
         eulers[i*primess[j]]=eulers[i]*eulers[primess[j]];
         if(i%primess[j]==0)
         {
          eulers[i*primess[j]]=eulers[i]*primess[j];
          break;
          }
      }
   }
}
int DETERMINATION()
{
     int c;
     primes();
     scanf("%d",&c);
     int cnt=1;
     while(c--)
     {
        int n;
        scanf("%d",&n);
        ll answer=0;
        for(int i=0;i<=n;i++)
          answer+=eulers[i];//0-n的欧拉函数值和
          answer*=2;//x,y两维的总和
          answer+=3;//特殊点(0,0)(1,0)(0,1)
        printf("%d %d %d\n",cnt++,n,answer);
     }
     return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43874261/article/details/88373682