• [poj 3090]Visible Lattice Point[欧拉函数]


    找出N*N范围内可见格点的个数.

    只考虑下半三角形区域,可以从可见格点的生成过程发现如下规律:

    若横纵坐标c,r均从0开始标号,则

    (c,r)为可见格点 <=>r与c互质

    证明:

    若r与c有公因子1<b<min(r,c),则(c/b, r/b)在线段(0, 0)(c, r)上,则(c, r)不是可见格点.(充分性)

    若r与c互质,显然线段上不存在整点,则(c, r)不是可见格点.(必要性)


    φ(n)表示不超过n且与n互素的正整数的个数,称为n的欧拉函数值

    也就是横坐标增1后纵坐标合法数目,即新增可见格点数(下半三角形区域).用时应乘二.

    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    int ans[1005];
    //由欧拉公式
    //phi(m) = m * (p1-1)/p1 * (p2-1)/p2 * .. * (pn-1)/pn. pi为大于1且不超过m的与m互质的数
    
    int eular(int n)
    {
        int s,i,m;
        m=(int)sqrt(n+0.5);//出于精度问题考虑,其实就是开根号向下取整
        s=n;
        for(i=2; i<=m; i++)
            if(n%i==0)//i是n的因数(如何保证是质数?看下文)
            {
                s=s/i*(i-1);//欧拉公式是连乘的,一项项乘
                while(n%i==0)
                    n/=i;///去掉n中所有i因数,也就相当于筛掉了n中的i的倍数,使得此后i的倍数都不能整除"n"
            }///那么下一个能够整除n的i一定是质数
        if(n>1)
            s=s/n*(n-1);
        return s;
    }
    int main()
    {
        int n,i,t,cas=1;
        scanf("%d",&t);
        ans[1]=3;
        for(i=2; i<=1000; i++)
            ans[i]=ans[i-1]+eular(i)*2;
        while(t--)
        {
            scanf("%d",&n);
            printf("%d %d %d
    ",cas++,n,ans[n]);
        }
        return 0;
    }
    

    自己敲一遍~

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int MAXN = 1005;
    int ans[MAXN];
    int eular(int n)
    {
        int i,s,m;
        m = (int)sqrt(n+0.5);
        s = n;
        for(i = 2;i <= m;i++)
        {
            if(!(n%i))
            {
                s = s / i * (i-1);
                while(!(n%i))
                    n /= i;
            }
        }
        if(n>1)
            s = s / n * (n-1);
    ///假设n可以分解为(升序排列)p[1], p[2], .. p[n-1], p[n]那么√n > p[n-1]
    ///反之 则 √n <= p[n-1]
    ///      => n <= p[n-1]*p[n-1] < p[n-1]*p[n] < p[1]*p[2]*..*p[n-1]*p[n] = n   矛盾
    ///因此,循环结束时,最多只剩下1个质因子.
        return s;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        memset(ans,0,sizeof(ans));
        int last = 0;
        ans[0] = 1;
        for(int k=1;k<=T;k++)
        {
            int n;
            scanf("%d",&n);
            if(last>=n)
            {
                printf("%d
    ",ans[n]);
                continue;
            }
            for(int i=last+1;i<=n;i++)
            {
                ans[i] = ans[i-1] + 2*eular(i);
               // printf("eular(%d) = %d
    ",i,eular(i));
            }
            last = n;
            printf("%d %d %d
    ",k,n,ans[n]);
        }
    }


  • 相关阅读:
    linux sort,uniq,cut,wc命令详解
    Linux IO实时监控iostat命令详解
    uniq命令
    四层和七层负载均衡的区别
    keepalived 和 heartbeat对比
    LVS+Keepalived实现负载均衡
    Lvs+heartbeat高可用高性能web站点的搭建
    使用 awk 过滤文本或文件中的字符串
    最全mysql的复制和读写分离
    伤不起
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3253845.html
Copyright © 2020-2023  润新知