zoukankan      html  css  js  c++  java
  • P2158 [SDOI2008]仪仗队

    传送门

    可以发现图是对称的

    所以我们先只考虑下半部分,不包括y=x的点

    如果能算出下半部分总和为ans

    那么答案就是 ans*2+1(加上y=x的方向有一个同学)

    以观察者为原点,建立直角坐标系:

    那么下半部分的视线的斜率≥0且<1,ans就是不同的斜率数量

    从左到右,从下到上考虑每个点(x,y)

    它能对答案有贡献当且仅当 x,y,互质

    因为如果 x,y 不互质,从原点看x,y的视线的斜率就是x/y= (x/gcd(x,y)) / (y/gcd(x,y))

    因为点(x/gcd(x,y)  ,   y/gcd(x,y)) 的点之前已经被考虑过了

    所以从原点到(x,y)的视线的斜率也被考虑过了,所以点(x,y)没有对答案产生贡献

    如果x,y互质说明这一个斜率之前还没有被其他点"使用"(十分显然)

    那就是求 1~n 中每一个小于 n 数 x      的小于x的与 x 互质的数的个数

    就是求 1~n 中每一个小于 n 数 x的欧拉函数和

    直接线性求出所有欧拉函数值就好了:

    注意特判n=1的情况,因为观察者看不到自己所以答案为0

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int N=1e5+7;
    int pri[N],cnt,phi[N];
    bool not_pri[N];
    int n,ans;
    void pre()
    {
        not_pri[1]=phi[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(!not_pri[i]) { pri[++cnt]=i; phi[i]=i-1; }
            for(int j=1;j<=cnt;j++)
            {
                int g=i*pri[j];
                if(g>n) break;
                not_pri[g]=1;
                if(!(i%pri[j])) { phi[g]=phi[i]*pri[j]; break; }
                phi[g]=phi[i]*phi[pri[j]];
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        if(n==1) { printf("0"); return 0; }//特判
        pre();
        for(int i=1;i<n;i++) ans+=phi[i];
        printf("%d",ans*2+1);
        return 0;
    }
  • 相关阅读:
    【BZOJ】2729: [HNOI2012]排队
    【BZOJ】2734: [HNOI2012]集合选数
    【BZOJ】3573: [Hnoi2014]米特运输
    【BZOJ】4008: [HNOI2015]亚瑟王
    【BZOJ】[HNOI2015]菜肴制作
    数论六·模线性方程组
    数论五·欧拉函数
    黄金矿工
    数论四·扩展欧几里德
    数论三·约瑟夫问题
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9779225.html
Copyright © 2011-2022 走看看