P2158 [SDOI2008]仪仗队
题目描述
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。 现在,C君希望你告诉他队伍整齐时能看到的学生人数。
输入输出格式
输入格式:
共一个数N
输出格式:
共一个数,即C君应看到的学生人数。
输入输出样例
说明
【数据规模和约定】
对于 100% 的数据,1 ≤ N ≤ 40000
//Pro:P2158 [SDOI2008]仪仗队 //把图上的(1,1)看作是(0,0) //因为正方形关于对角线对称 //所以我们只考虑对角线一侧的三角形 //可以发现,在一条直线上的点会被这条直线上第一个点遮挡 //所以如果被遮挡的话,那么他们所在直线的斜率相等 //设有一条直线上的一个点是(x,y) //那么这条直线的斜率k=y/x //然后我们就可以知道这条线上的第一个点(x0,y0) //且gcd(x0,y0)=1,(x0*t,y0*t)都会被(x0,y0)遮挡 //所以问题就变成了求 sigma(i=2->n-1) // (j=1->i) // gcd(i,j)=1 //也就是求sigma(i=2->n-1) phi(i) //当然最后还要再*2+3 //因为我们算的是三角,而且没有算(0,1),(0,1),(1,1) #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=5e4+5; bool flag[N]; int prime[N],cnt; int phi[N]; void init(int n) { int d; flag[1]=1,phi[1]=1; for(int i=2;i<n;++i) { if(!flag[i]) prime[++cnt]=i,phi[i]=i-1; for(int j=1;j<=cnt&&(d=i*prime[j])<n;++j) { flag[d]=1; if(i%prime[j]) phi[d]=phi[i]*(prime[j]-1); else phi[d]=phi[i]*prime[j]; } } } int n,ans; int main() { scanf("%d",&n); if(n==1) { puts("0"); return 0; } init(n); for(int i=2;i<n;++i) ans+=phi[i]; printf("%d",ans*2+3); return 0; }