P2158 [SDOI2008]仪仗队 题解

旅行传送门:https://www.luogu.com.cn/problem/P2158c++

题目描述

做为体育委员,C君负责此次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(以下图)。ide

如今,C君但愿你告诉他队伍整齐时能看到的学生人数。函数

 

输入格式

共一个数N优化

输出格式

共一个数,即C君应看到的学生人数。spa

输入输出样例

输入 #1
4
输出 #1
9

 解题思路

以左下角C君所在的点为原点,第一行为x轴,第一列为y轴创建平面直角坐标系。不难发现,一条直线上只有第一个点能被看见,而直线的斜率 k = y / x,即点(x , y)能被看见的条件为其与原点的连线的斜率是第一次出现;咱们又知道,分数化为最简形式时有:gcd (x , y) = 1,即x与y互质,那么咱们的问题就转化为了求有几对互质的x与y。code

在数论中,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(所以φ(1)=1)。所以,方阵下三角中互质的x与y的对数即为(方阵为n * n的大小,而坐标轴的起点是由0开始计算,因此只累加至n - 1),因为方阵关于y = x对称,最后输出答案2 *  + 1便可(y = x 上还有一点)。orm

欧拉函数

 

度娘与各大神犇对该函数的证实过程远远赛过本蒟蒻,在此就不过多赘述了。blog

AC代码

 1 //打表版(3~6s)
 2 #include <bits/stdc++.h>
 3 #define MAXN 40000 + 10
 4 
 5 int phi[MAXN],ans[MAXN];
 6 
 7 void euler()
 8 {
 9     ans[1] = 1;
10     for (int i = 1; i <= MAXN; i++)
11     {
12         int res = i, n = i;
13         for (int j = 2; j * j <= n; j++)
14         {
15             if (!(n % j))
16                 res = res * (j - 1) / j;
17             while (!(n % j))
18                 n /= j;
19         }
20         if (n > 1)
21             res = res * (n - 1) / n;
22         phi[i] = res;
23     }
24     for (int i = 2; i <= MAXN; i++)
25         for (int j = 1; j < i; j++)
26             ans[i] += phi[j];
27 }
28 
29 int main(int argc, char const *argv[])
30 {
31     euler();
32     int n;
33     while (~scanf("%d", &n))
34     {
35         if (n == 1) //方阵大小为1*1时特判,此时队列中只有本身,输出0
36         {
37             puts("0");
38             continue;
39         }
40         printf("%d\n", 2 * ans[n] + 1);
41     }
42     return 0;
43 }
View Code
 1 //优化版(55±5ms)
 2 #include <bits/stdc++.h>
 3 #define MAXN 40000 + 10
 4 
 5 int main(int argc, char const *argv[])
 6 {
 7     int n, ans;
 8     while (~scanf("%d", &n))
 9     {
10         ans = 0;
11         if (n == 1)
12         {
13             printf("%d\n", 0);
14             continue;
15         }
16         for (int i = 1; i < n; i++)
17         {
18             int res = i, t = i;
19             for (int j = 2; j * j <= t; j++)
20             {
21                 if (!(t % j))
22                     res = res * (j - 1) / j;
23                 while (!(t % j))
24                     t /= j;
25             }
26             if (t > 1)
27                 res = res * (t - 1) / t;
28             ans += res;
29         }
30         printf("%d\n", 2 * ans + 1);
31     }
32     return 0;
33 }
View Code
相关文章
相关标签/搜索