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;
    }
  • 相关阅读:
    [android] 实现返回键操作思路
    [android] 切换界面的问题
    [android] 切换界面的通用处理
    [android] 界面切换的简单动画
    [android] 界面切换的核心方法
    [android] 标题部分管理
    [android] 界面的划分
    [android] socket在手机上的应用
    [android] 网络链接类型和渠道
    [android] android通信协议
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9779225.html
Copyright © 2011-2022 走看看