仪仗队(luogu 2158)

题目描述

作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。

  

现在,C君希望你告诉他队伍整齐时能看到的学生人数。

输入输出格式

输入格式:

 

共一个数 N

 

输出格式:

 

共一个数,即C君应看到的学生人数。

 

输入输出样例

输入样例
4
输出样例
9

说明

【数据规模和约定】

对于 100% 的数据,1 ≤ N ≤ 40000

 


 思路:

从图中可以很明显看出,原点只能看到斜率相同的线最先射到的点,也就是说,每一条不同斜率的视线,仅且只有一个点

因为这个图是关于 y=x 对称的,所以我们只需要考虑一边

 

设原点O(0,0)【方便起见】,y=x下半部分可以看到的点有:

(2,1) (3,1) (4,1) (5,1) 

    (3,2) (4,3) (5,2)

           (5,3)

           (5,4)

有一个很显然的结论:当gcd(x,y)=1时,就是可以该斜率可以看到的点

因为和他斜率相同的点一定是(kx,ky),换句话说,当x,y互质时,就是满足条件的点

所以,本题转变为了求 2~N 的欧拉函数之和

 

Attention:

  1. 在计算时我们排除了三个特殊点,所以 ans=3+2*euler()
  2. 注意特判 1 !

code

#include<stdio.h> 
#include<algorithm> 
using namespace std;
const int MX=41000;
int n,ans;
int phi[MX];

int euler() 
{
    for(int i=2;i<=n;++i) phi[i]=i;
    for(int i=2;i<=n;++i) 
        if(i==phi[i]) { 
            for(int j=i;j<=n;j+=i) {
                phi[j]=phi[j]/i*(i-1);
            }
        }
    int tot=0;
    for(int i=2;i<=n;++i) {
        tot+=phi[i];
    }
    return tot;
}

int main() 
{
    scanf("%d",&n);
    if(n==1) {
        printf("0");
        return 0;
    }
    n--;
    ans=(3+2*euler());
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-10-14 21:21  qseer  阅读(381)  评论(0编辑  收藏  举报