Description
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N 的方阵,为了保证队伍在行进中整齐划一,C 君会跟在仪仗队的生后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C 君希望你告诉他队伍整齐时能看到的学生人数。
Input
共一个数N。
Output
共一个数,即C 君应看到的学生人数。
Sample Input
4
Sample Output
9
Data Constraint
Hint
【数据规模和约定】
对于30 %的数据,1 <= N <= 1000
对于100 %的数据,1 <= N <= 40000
The Solution
首先这个矩阵是对称的,我们可以先只看一半。
仔细观察我们可以发现若(x,y)是可看见的点,那么他们满足gcd(x,y)=1.
即:如果可看见的点都是x/y的最简式的形式。
理由如下:
因为如果可以再化简,则说明其最简式一定被看过了。
所以
题目就转换成在1 ~N的范围内x,y互质的个数。
而我们是只看半的,所以左后结果要*2,而其中(1,1)是特别的,最后要剪掉。
而最后结果存在(0,1),(1,0)随意答案要加2.
所以最后可以这样表示.
Ans=2∗∑n−1I=1ϕ(i)+1
求phi可以用线筛,也可以用普通方法。
把这道题当成线筛phi模板题了 。。。
CODE
线筛版:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cmath>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define N 40005
using namespace std;
typedef long long ll;
int Phi[N],Pre[N],ans = 0;
int Prime[N],tot = 0,n;
bool bz[N];
void PHI()
{
Phi[1] = 1;
fo(i,2,n)
{
if (!bz[i]) Phi[i] = i - 1,Prime[++ tot] = i;
fo(j,1,tot)
{
int x = Prime[j];
if (i * x > n) break;
bz[i * x] = true;
if (i % x == 0)
{
Phi[i * x] = Phi[i] * x;
break;
}
else Phi[i * x] = Phi[i] * Phi[x];
}
}
}
int main()
{
scanf("%d",&n);
PHI();
fo(i,1,n - 1) ans = ans + Phi[i];
printf("%d\n",ans * 2 + 1);
}
普通phi
#include <cstdio>
#include <iostream>
#include <cmath>
#define fo(i,a,b) for (int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
ll ans = 0;
ll PHI(int x)
{
ll res = x;
fo(i,2,(int)sqrt(x))
{
if (x % i == 0)
{
res = res * (ll)(i - 1) / i;
while (x % i ==0) x /= i;
}
}
if (x > 1) res = res * (ll)(x - 1) / x;
return res;
}
int main()
{
int n;
scanf("%d", &n);
fo(i,1,n-1) ans += PHI(i);
printf("%lld\n",ans * 2 + 1);
}