题目描述:
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C君希望你告诉他队伍整齐时能看到的学生人数。
解析:
观察发现,以观察点的右上为第1行第1列,则能被看到的点(x,y)在第x行第y列,必须满 **gcd(x,y)==1** 才能被看到,
由图的对称性故最后答案应为:
2×(Φ(2)+Φ(3)+....+Φ(N−1))+3
2
×
(
Φ
(
2
)
+
Φ
(
3
)
+
.
.
.
.
+
Φ
(
N
−
1
)
)
+
3
最后加3是对角线、左、右能看到的人。
/*
由于(k*x,k*y) 会被 (x,y) 遮挡,于是要求出 gcd(x,y)==1 的个数,即为欧拉函数,但要乘上2,再加上(0,1),(1,0),(1,1)
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<set>
#define rep(a,b,c) for(register int a=b;a<=c;a++)
#define REP(a,b,c,d) for(register int a=b;a<=c;a+=d)
#define Set(a,b) memset(a,b,sizeof(a))
#define frep(a,b,c) for(register int a=b;a>=c;a--)
#define Start(x) for(register int v,i=head[now];i;i=a[i].next)
using namespace std;
const int N=1e7+10;
bool vis[N];
int prime[N];
int phi[N];
int main()
{
int n;
scanf("%d",&n);
vis[1]=1;vis[0]=1;
register int tot=0;
phi[1]=1;
phi[0]=0;
rep(i,2,n){
if(!vis[i]) {prime[++tot]=i;phi[i]=i-1;}
rep(j,1,tot){
if(1ll*i*prime[j]>n) break;
vis[i*prime[j]]=1;
if(i%prime[j]==0) {
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(phi[prime[j]]);
}
}
register int ans=0;
rep(i,2,n-1){
ans+=phi[i];
}
printf("%d\n",(ans<<1)+3);
return 0;
}