SDOI2008 仪仗队

来源:互联网 发布:温州网络瘫痪 编辑:程序博客网 时间:2024/04/30 03:07
题目描述 Description

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

  现在,C君希望你告诉他队伍整齐时能看到的学生人数。

 

 

输入描述 Input Description

  共一个数N。

输出描述 Output Description

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

样例输入 Sample Input

4

样例输出 Sample Output

9

 

数据范围及提示 Data Size & Hint

对于 30% 的数据,1≤N≤1000

对于 100% 的数据,1≤N≤40000

 

 

  一开始这个题目在CODEVS上的样例输出是错的,让我想了半天,直到佣神帮我把数据改过来。

  我们可以把最左下角当作(0,0),然后最右上角自然就是(N-1, N-1),想一想就会发现,如果一个点(X,Y)可以被观测到,那么(KX, KY)就无法被观察到,因为从左下角看过去,这两个点在同一条直线上。

  还有一点很容易证明的是,这张图沿着左下-右上这条对角线分开,两部分是对称的,一个比较需要注意的是(1,1)并不属于其中任何一部分,而是在对角线上。

  把其中一部分删去后,我们就得到了一个三角形,根据前边标红的性质,对于第N行,我们只需要求出小于等于N且和N互质的正数有多少个就好,这时候我们就可以用到欧拉函数来求解。

  把小于等于N且和N互质的数的个数设为phi(N),比如phi(8) = 4,因为1,3,5,7和8互质。

  phi(x) = x* (1 - 1/p1) * (1 - 1/p2) ... * (1 - 1/pn)

  其中的p1到pn分别为x的n个质因数,需要注意的是,每个质因数只被计算一遍,比如12=2*2*3  phi(12) = 12*(1/2)*(2/3) = 4。

  求出phi(2)到phi(n - 1)的和并乘二之后,我们需要特别处理第零列和第零行上的两个点和(1,1)这个点,也就是加上3(第零行和第零列的点可以不特殊处理而是将phi(0)设为1)。

 

代码如下(求不吐槽风格)

复制代码
 1 #include<iostream> 2 using namespace std; 3  4 int ans, n, a[40001]; 5  6 int main() { 7     cin >> n; 8     n = n - 1; 9     for (int i = 1; i <= n; i++)10         a[i] = i;        //PHI(I)11     for (int i = 2; i <= n; i++)      //筛法求phi(i)12         if (a[i] == i) {13             int p = 1;14             while (p * i <= n) {15                 a[p * i] = a[p * i] / i * (i - 1);16                 p++;17             }18         }19     for (int i = 1; i <= n; i++)20         ans += a[i];21     ans = ans * 2 + 1;   //(1,1)被计算两次,(0,1)(1,0)没被计算。 22     cout << ans;23     return 0;24 }            
复制代码

 

 

0 0
原创粉丝点击