http://poj.org/problem?id=3090
题目大意:你站在(0,0)的点上看向第一向限的点,点和点会互相阻挡,问最多看到多少点。
很容易想到,我们能看到的点,它的横纵坐标一定是互质的,那么怎么求呢?
首先我们要知道一个东西叫做法雷级数:
F1:0/1 1/1
F2:0/1 1/2 1/1
F3:0/1 1/3 1/2 2/3 1/1
F4:0/1 1/4 1/3 1/2 2/3 3/4 1/1
F5:0/1 1/5 1/4 1/3 2/5 1/2 3/5 2/3 3/4 4/5 1/1
F6:0/1 1/6 1/5 1/4 1/3 2/5 1/2 3/5 2/3 3/4 4/5 5/6 1/1
……
我们发现新加进来的数,它的分母为n,分子与n互质,所以加入了与n互质的数的个数。
是不是欧拉函数啊(叫做E)
所以Fn=Fn-1+En
但是我们知道我们要求的F可以分子分母相反,那么实际我们求的是Fn*2-1(-1因为1/1)
#include<cstdio> #include<cctype> #include<iostream> using namespace std; inline int read(){ int X=0,w=0; char ch=0; while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } int f[1001],e[1001]; bool h[1001]; int p[1001],cnt=0; void Euler(int n){ e[1]=1; for(int i=2;i<=n;i++){ if(!h[i]){ cnt++; p[cnt]=i; e[i]=i-1; } for(int j=1;j<=cnt&&i*p[j]<=n;j++){ h[i*p[j]]=1; if(i%p[j]==0){ e[i*p[j]]=e[i]*p[j]; break; } e[i*p[j]]=e[i]*(p[j]-1); } } return; } void Farley(int n){ f[1]=2; for(int i=2;i<=n;i++){ f[i]=f[i-1]+e[i]; } return; } int main(){ Euler(1000); Farley(1000); int c=read(); for(int i=1;i<=c;i++){ int n=read(); printf("%d %d %d ",i,n,f[n]*2-1); } return 0; }