Description
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C君希望你告诉他队伍整齐时能看到的学生人数。
Input
共一个数N。
Output
共一个数,即C君应看到的学生人数。
Sample Input
4
Sample Output
9
HINT
【数据规模和约定】 对于 100% 的数据,1 ≤ N ≤ 40000
Source
数论
格点上,两格点之间的连线经过的格点数为 gcd(Δx,Δy)−1 ,需要对某些点特判。
于是我们要求的就是 gcd(x−1,y−1)−1=0 的点的个数。
因为是对称的,只看一边。看右下角那一边,按列来看,答案就是列号的欧拉函数。还要特判(1,1)这个点,加上即可。
筛一遍phi,再求前缀和。
代码:
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int SZ = 1000010;
int n;
int phi[SZ],pri[SZ],sum[SZ];
bool vis[SZ];
void get_phi()
{
phi[1] = 1;
for(int i = 2,tot = 0;i <= n;i ++)
{
if(!vis[i]) pri[++ tot] = i,phi[i] = i - 1;
for(int j = 1,m;j <= tot && (m = i * pri[j]) <= n;j ++)
{
vis[m] = 1;
if(i % pri[j] == 0)
{
phi[m] = phi[i] * pri[j];
break;
}
else
{
phi[m] = phi[i] * phi[pri[j]];
}
}
}
for(int i = 1;i <= n;i ++)
{
sum[i] = sum[i - 1] + phi[i];
}
}
int main()
{
scanf("%d",&n);
get_phi();
printf("%d",sum[n - 1] * 2 + 1);
return 0;
}