[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 于 福州