《算法竞赛进阶指南》0x32欧拉函数 POJ3090 Visible Lattice Points

题目链接:http://poj.org/problem?id=3090

从(0,0)向周围看去,能在(N,N)点以内看到的点的个数,假设x,y不是互质的,那么一定存在一个点(x/d,y/d)在(x,y)前面被看到,所以看到的点的x和y 一定是互质的,我们只需要扫描一遍n>=y>x.=2中的y就可以,对于一个y我们只要知道2<=x<y中有多少个数是跟它互质的,就是欧拉函数的前缀和,可以在O(N)时间内用最小质数筛法求出来。最后再对称回去就可以了。

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
#define maxn 1010
int sum[maxn],phi[maxn];
int n;
int v[maxn];
vector<int> prime;
void get_prime(int n){
    memset(v,0,sizeof(v));
    for(int i=2;i<=n;i++){
        if(!v[i]){
            v[i]=i;prime.push_back(i);
            phi[i]=i-1;
        }
        for(int j=0;j<prime.size();j++){
            if(prime[j]>v[i] || prime[j]>n/i )break;
            v[i*prime[j]]=prime[j];
            //当p|n 且p^2|n时,phi[n]=phi[n/p]*p
            //当 当p|n 且p^2不能整除n时,phi[n]=phi[n/p]*(p-1)
            phi[i*prime[j]] = phi[i]* (i%prime[j]?prime[j]-1:prime[j]);
        }
    }
}
int main(){
    get_prime(1008);
    
//    for(int i=1;i<=100;i++){
//        cout<<phi[i]<<" ";
//        if((i-1)%10 == 0 && i-1)cout<<endl;
//    }
    for(int i=2;i<1008;i++)sum[i]=sum[i-1]+phi[i];
    int T=0,num;
    cin>>num;
    while(num--){
        scanf("%d",&n);
        printf("%d %d %d\n",++T,n,3+2*sum[n]);
    } 
} 

 

posted @ 2020-06-23 08:44  WA自动机~  阅读(213)  评论(0编辑  收藏  举报