题目描述
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如右图)。 现在,C君希望你告诉他队伍整齐时能看到的学生人数。
输入输出格式
输入格式:
共一个数N
输出格式:
共一个数,即C君应看到的学生人数。
思路:
典型的欧拉筛
为了帮助萌新,我先从欧拉函数开讲
什么是欧拉函数?
定义:与一个数的约数有且只有1的数(互质)的个数(比如说2有1一个,6有1,5两个)
性质:积性函数(Phi(i)等于他的所有质因数的phi值的乘积)
为什么能这么做呢?
其实这道题求的是有多少种不同的斜率
为什么呢?
看图:
很显然,一个斜率上只能看到一个人,该斜率其他人都会被堵得死死的。。。
那么,每一个独立的斜率又如何表示呢?
我们用数对(x,y)表示斜率
我们知道,如果x,y不互质,那么他们可以同时除以他们的最大公约数(设为k),则该斜率可表示为(x/k,y/k)
很显然会有重复
所以为了避免重复,我们所求的是互质点对的个数
互质点对很显然就是欧拉函数
这里我用的是(nlogn)的算法——埃氏筛
从2开始,一个数i如果因数标记为1,则他是素数,他的欧拉函数值为i-1,同时,利用它来更新所有它的倍数的因数标记,如果因数标记大于1,则其不是素数,根据积性函数的性质,Phi[i]=其各因数的乘积,当其含有多次方因子时(比如8=2^3),那么Phi[i]的值为phi[2]*2*2;
不说了,代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
long long ll;
long long e[40010];
long long n,ans;
int main()
{
ans=2;
cin>>n;
if(n==1)
{
cout<<0;
return 0;
}
for(int i=1;i<=n;++i)
{
e[i]=i;
}
for(int i=2;i<=n;++i)
{
if(e[i]==i)
{
for(int j=i;j<=n;j+=i)
{
e[j]=e[j]/i*(i-1);
}
}
}
n--;
for(int i=2;i<=n;++i)
{
ans+=e[i]*2;
}
cout<<ans+1;
}