P2158 [SDOI2008]仪仗队

题目描述

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

输入输出格式

输入格式:

 

共一个数N

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
4
输出样例#1: 复制
9

说明

【数据规模和约定】

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

 

 

//Pro:P2158 [SDOI2008]仪仗队

//把图上的(1,1)看作是(0,0)
//因为正方形关于对角线对称
//所以我们只考虑对角线一侧的三角形
//可以发现,在一条直线上的点会被这条直线上第一个点遮挡
//所以如果被遮挡的话,那么他们所在直线的斜率相等 
//设有一条直线上的一个点是(x,y)
//那么这条直线的斜率k=y/x
//然后我们就可以知道这条线上的第一个点(x0,y0)
//且gcd(x0,y0)=1,(x0*t,y0*t)都会被(x0,y0)遮挡 
//所以问题就变成了求 sigma(i=2->n-1)
//                            (j=1->i)
//                               gcd(i,j)=1
//也就是求sigma(i=2->n-1) phi(i) 
//当然最后还要再*2+3
//因为我们算的是三角,而且没有算(0,1),(0,1),(1,1) 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=5e4+5;

bool flag[N];
int prime[N],cnt;
int phi[N];
void init(int n)
{
    int d;
    flag[1]=1,phi[1]=1;
    for(int i=2;i<n;++i)
    {
        if(!flag[i])
            prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt&&(d=i*prime[j])<n;++j)
        {
            flag[d]=1;
            if(i%prime[j])
                phi[d]=phi[i]*(prime[j]-1);
            else
                phi[d]=phi[i]*prime[j];
        }
    }
}

int n,ans;
int main()
{
    scanf("%d",&n);
    if(n==1)
    {
        puts("0");
        return 0;
    }
    init(n);
    for(int i=2;i<n;++i)
        ans+=phi[i];
    printf("%d",ans*2+3);
    return 0;
}

 

posted @ 2018-07-01 15:07  whymhe  阅读(435)  评论(0编辑  收藏  举报