欧拉函数 – Visible Lattice Points – POJ 3090

在一个平面直角坐标系的第一象限内,如果一个点(x,y)与原点(0,0)的连线中没有通过其他任何点,则称该点在原点处是可见的。

例如,点(4,2)就是不可见的,因为它与原点的连线会通过点(2,1)。

部分可见点与原点的连线如下图所示:

编写一个程序,计算给定整数N的情况下,满足0≤x,y≤N的可见点(x,y)的数量(可见点不包括原点)。

输入格式

第一行包含整数C,表示共有C组测试数据。

每组测试数据占一行,包含一个整数N。

输出格式

每组测试数据的输出占据一行。

应包括:测试数据的编号(从1开始),该组测试数据对应的N以及可见点的数量。

同行数据之间用空格隔开。

数据范围

1 ≤ N , C ≤ 1000 1≤N,C≤1000 1N,C1000

输入样例:

4
2
4
5
231

输出样例:

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

分析:

在 点 阵 中 , 任 意 两 点 ( x 1 , y 1 ) 、 ( x 2 , y 2 ) 的 连 线 L , L 不 经 过 其 他 格 点 的 充 要 条 件 是 : 在点阵中,任意两点(x_1,y_1)、(x_2,y_2)的连线L,L不经过其他格点的充要条件是: (x1,y1)(x2,y2)线LL

y 2 − y 1 x 2 − x 1 是 最 简 整 数 比 , 即 g c d ( y 2 − y 1 , x 2 − x 1 ) = 1 。 \frac{y_2-y_1}{x_2-x_1}是最简整数比,即gcd(y_2-y_1,x_2-x_1)=1。 x2x1y2y1gcd(y2y1,x2x1)=1

很 好 理 解 。 因 为 , 假 设 存 在 x 2 − x 1 = 2 , y 2 − y 1 = 2 , 如 下 图 很好理解。因为,假设存在x_2-x_1=2,y_2-y_1=2,如下图 x2x1=2y2y1=2

则 存 在 ( x 3 , y 3 ) , 使 得 y 3 − y 1 = 1 2 ( y 2 − y 1 ) , x 3 − x 1 = 1 2 ( x 2 − x 1 ) 则存在(x_3,y_3),使得y_3-y_1=\frac{1}{2}(y_2-y_1),x_3-x_1=\frac{1}{2}(x_2-x_1) (x3,y3)使y3y1=21(y2y1)x3x1=21(x2x1)

本题:

本 题 已 固 定 一 点 ( 0 , 0 ) , 问 题 即 求 点 对 ( x , y ) 的 数 量 , 满 足 g c d ( x , y ) = 1 。 本题已固定一点(0,0),问题即求点对(x,y)的数量,满足gcd(x,y)=1。 (0,0)(x,y)gcd(x,y)=1

由 于 图 关 于 y = x 对 称 , 我 们 仅 需 计 算 一 半 再 乘 2 即 可 。 由于图关于y=x对称,我们仅需计算一半再乘2即可。 y=x2

g c d ( x , y ) = 1 , 即 x 与 y 互 质 , gcd(x,y)=1,即x与y互质, gcd(x,y)=1xy

我 们 从 横 坐 标 逐 个 递 增 统 计 , 就 是 对 每 一 个 x , 统 计 [ 1 , x − 1 ] 中 , 与 x 互 质 的 数 的 个 数 。 我们从横坐标逐个递增统计,就是对每一个x,统计[1,x-1]中,与x互质的数的个数。 x[1,x1]x

这 就 将 问 题 转 化 为 求 欧 拉 函 数 。 这就将问题转化为求欧拉函数。

答 案 : ∑ i = 1 n ϕ ( i ) × 2. 答案:\sum_{i=1}^n\phi(i)×2. i=1nϕ(i)×2.

代码:

#include<iostream>

using namespace std;

const int N=1010;

int primes[N],cnt;
bool st[N];
int phi[N];

void get_prime(int n)
{
    for(int i=2;i<=n;i++)
    {
        phi[1]=1;
        if(!st[i]) 
        {
            phi[i]=i-1;
            primes[cnt++]=i;
        }
        for(int j=0;primes[j]*i<=n;j++)
        {
            st[primes[j]*i]=true;
            if(i%primes[j]==0)
            {
                phi[i*primes[j]]=phi[i]*primes[j];
                break;
            }
            phi[i*primes[j]]=phi[i]*(primes[j]-1);
        }
    }
}

int main()
{
    get_prime(N-1);
    
    int n,m;
    cin>>m;
    for(int T=1;T<=m;T++)
    {
        cin>>n;
        int res=1;
        for(int i=1;i<=n;i++) res+=phi[i]*2;
        cout<<T<<' '<<n<<' '<<res<<endl;
    }
    return 0;
}

本文地址:https://blog.csdn.net/njuptACMcxk/article/details/107343621