[FZSZOJ 1026] 观察者

题目描述

魔法学院的期末考开始了。
校长Jacobi用魔法在考场生成了一个观察者,以观察考场情况。
整个考场可以看成一个xOy平面,N*N个考生的坐标为(p,q) (1<=p,q<=N, p,q∈Z+),而观察者的坐标为(0,0)。
但是问题来了,就算在把考生抽象成点的理想情况下,Jacobi的观察者也看不到所有考生的动向,这是因为有一些考生被另一些考生遮住了。
现在Jacobi想知道他的观察者在理想情况下能看到多少个考生。

输入

输入文件watcher.in的第一行包含一个正整数N。

输出

输出文件watcher.out包含一个正整数,意义见问题描述。

样例输入

3

样例输出

7

提示

[数据规模]

对于40%的数据:N<=1000。

对于80%的数据:N<=1000000。

对于100%的数据:1<=N<=10000000。

[注意事项]

本题代码长度不得超过2KB。

 

【分析】

看到这题,前面想的是几何,后面用几何推导出了一个式子

如果前面被人挡住了,那么连接观察者(0,0)与这个点(p,q)一定还经过一个点(r,s),而且r<p,s<q,观察发现这是一个正比例图像,那么(p,q)可表示为(rn,sn)(n≥1且为正整数),那么只要一点的横纵坐标互质,就能被观察者观察到。

那么我们得到了O(N)算法:

枚举i∈[1,n],对于每一个i求phi(i)(欧拉函数)即可,根据对称性,乘以2,然后减去1(第一行的那个,即phi(1),被重复计算了两次那么即可算出答案

那么,我们还需要一个预处理phi值的函数,我们来介绍一下欧拉筛。

首先,以下公式容易推出:

phi(n)=n(1-1/p1)(1-1/p2)...(1-1/pk)

其中,p1..k表示n的质因数分解所分解出的质数

根据这个我们可以推出欧拉筛算法(具体可百度一下)

【PS.这段楼主今晚理解下再更】

那么,我们就有了代码

#include<iostream>
#include<stdio.h>
using namespace std;
int phi[10000010];
int n;
long long cnt=0;
int prime[1000010],tot;
bool check[10000010];
int main() {
    int n;
    scanf("%d",&n);
    phi[1]=1;
    tot=0;
    for (int i=2;i<=n;++i) {
        if(!check[i]) {
            prime[tot++]=i;
            phi[i]=i-1;    
        }
        for(int j=0;j<tot;++j) {
            if(i*prime[j]>n) break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0) {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for (int i=1;i<=n;++i) cnt+=phi[i];
    cout<<cnt*2-1<<endl;
    return 0;
}

TonyFang

2015.5.13 于 福州

posted @ 2015-05-13 16:53  TonyFang  阅读(380)  评论(0编辑  收藏  举报