时空限制 1000ms / 128MB
题目描述
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C君希望你告诉他队伍整齐时能看到的学生人数。
输入格式:
共一个数N
输出格式:
共一个数,即C君应看到的学生人数。
【数据规模和约定】
对于 100% 的数据,1 ≤ N ≤ 40000
题目分析
一个坐标在
(
x
,
y
)
(x,y)
(x,y)的人能被看到当且仅当它与原点的连线上没有其他点
这个条件满足当且仅当
g
c
d
(
x
,
y
)
=
=
1
gcd(x,y)==1
gcd(x,y)==1时成立
因为若
g
c
d
(
x
,
y
)
=
=
d
,
d
!
=
1
gcd(x,y)==d,d!=1
gcd(x,y)==d,d!=1,则点
(
x
/
d
,
y
/
d
)
(x/d,y/d)
(x/d,y/d)一定在
(
x
,
y
)
(x,y)
(x,y)与原点的连线上
对于一个确定的行
y
y
y
这一行上满足条件的
x
x
x数恰好是
φ
(
y
)
\varphi(y)
φ(y)
(
1
≤
x
<
y
)
(1\leq x< y)
(1≤x<y)
这一点根据欧拉函数的定义不难证明
于是得
a
n
s
=
3
+
2
∗
∑
i
=
1
n
φ
(
i
)
ans=3+2*\sum_{i=1}^n\varphi(i)
ans=3+2∗∑i=1nφ(i)
注意由于第0行第0列特判为3个,所以要先
n
−
−
n--
n−−,以及注意特判
n
=
=
1
n==1
n==1的情况
利用线性筛求欧拉函数的话复杂度为 O ( n ) O(n) O(n)
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
int n,ans;
int phi[50010];
void euler(int n)
{
for(int i=1;i<=n;++i) phi[i]=i;
for(int i=2;i<=n;++i)
{
if(phi[i]==i)
for(int j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1);
}
}
int main()
{
n=read();
if(n==1){cout<<0;return 0;}
euler(--n);
for(int i=2;i<=n;++i)
ans+=phi[i];
printf("%d",ans*2+3);
return 0;
}