• 洛谷P2158 [SDOI2008]仪仗队


    题目描述

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

    输入输出格式

    输入格式:

    共一个数N

    输出格式:

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

    输入输出样例

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

    说明

    【数据规模和约定】

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

    有一个比较显然的结论,如果我们把教练所在的点看做坐标原点,建立坐标系

    那么一个点$(i,j)$能被看到,当且仅当$gcd(i,j)=1$。否则会被$dfrac {i}{gcd left( i,j ight) },dfrac {j}{gcd left( i,j ight) }$这个点挡住

    对于$x,y$轴,我们特殊判断一下

    这样问题就转化为求$sum ^{n-1}_{i=1}sum ^{n-1}_{i=1}left[ gcd left( i,j ight) =1 ight]$

    这是一个非常经典的问题

    我们不妨假设$i<j$,那么上面的公式就是$2*sum ^{n-1}_{i=1}varphi left( i ight)-1$(最后的-1可以理解为(1,1)这个点被重复计算了)

    最后再加上$i=0,j=0$的两个点

    #include<cstdio>
    using namespace std;
    const int MAXN=1e6+10;
    int prime[MAXN],phi[MAXN],vis[MAXN],tot=0;
    int main(){
        int N;
        scanf("%d",&N);N=N-1;
        if(N==0) {printf("0");return 0;}
        phi[1]=1;
        for (int i=2; i <= N ;i++)
        {
            if (!vis[i]) prime[++tot]=i,phi[i]=i-1;
            for (int j=1; j<=tot && i*prime[j]<=N ;j++) 
            {
                vis[ i*prime[j] ]=1;
                if(i%prime[j]) phi[ i*prime[j] ] = phi[i] * (prime[j]-1);
                else {phi[ i*prime[j] ] =phi[i] * prime[j];break;}
            }
        }
        for(int i=1; i <= N; i++)
            phi[i]=phi[i]+phi[i-1];
        printf("%d",phi[N]*2+1);
        return 0;
    }
  • 相关阅读:
    AVOID "throw e" !!!
    C++基本功: 全面掌握const, volatile 和 mutable关键字
    转贴:asp.netN层代码示例
    管理强类型生成器(Mgmtclassgen.exe) MSDN
    WMI 例子,获取MAC地址
    SQL Server: convert varbinary to varchar
    C++: memset, memcpy 和strcpy的根本区别
    巧妙突破win2003系统的种种限制
    Question about sql server's linked server
    iOS APP开发概述学习笔记001
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8405459.html
Copyright © 2020-2023  润新知