BZOJ2190 [SDOI2008] 仪仗队
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2190
Description
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。 现在,C君希望你告诉他队伍整齐时能看到的学生人数。
Output
共一个数N。
Output
共一个数,即C君应看到的学生人数。
Orz出题人,能把数论题变成这样子真不容易
LSJ教主的题解:
假设C君为(0, 0), 则右上方为(n - 1, n - 1).
一个点(x, y) 能被看到的前提是gcd(x, y) = 1, 所以 answer = ∑ phi(i) * 2 + 2 - 1 = ∑phi(i) * 2 + 1 ( 1 <= i < n ). +2是因为(1, 0), (0, 1) 两个点, -1是因为(1, 1)重复计算了
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #define rep(i,l,r) for(int i=l; i<=r; i++) 6 #define clr(x,y) memset(x,y,sizeof(x)) 7 using namespace std; 8 const int maxn = 40010; 9 int n,cnt=0,pri[maxn],phi[maxn]; 10 bool flag[maxn]; 11 void get_euler(){ 12 clr(flag,0); phi[1] = 1; 13 rep(i,2,n){ 14 if (!flag[i]) pri[++cnt] = i, phi[i] = i - 1; 15 for(int j = 1; j <= cnt && i*pri[j] <= n; j++){ 16 flag[i*pri[j]] = 1; 17 if (i % pri[j]) phi[i*pri[j]] = phi[i] * (pri[j] - 1); 18 else{ 19 phi[i*pri[j]] = phi[i] * pri[j]; 20 break; 21 } 22 } 23 } 24 } 25 int main(){ 26 scanf("%d",&n); 27 get_euler(); 28 int ans = 0; 29 rep(i,1,n-1) ans += phi[i] << 1; 30 printf("%d\n",ans+1); 31 return 0; 32 }