bzoj2190--仪仗队--欧拉函数
Description
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C君希望你告诉他队伍整齐时能看到的学生人数。
Input
共一个数N。
Output
共一个数,即C君应看到的学生人数。
Sample Input
4
Sample Output
9
HINT
【数据规模和约定】
对于 100% 的数据,1 ≤ N ≤ 40000
题解:
观察到此图是关于对角线对称的,考虑对于图的一半找规律。
对于每个能直接看到的点(x,y),必定会挡住它后面的点,这些点都可以用(k*x,k*y)来表示。
也就是说,点的横坐标和纵坐标应该是互质的。所以我们将问题抽象为:图的一半的点数,就是 x比y小且x与y互质的点的个数。
用欧拉函数得到以上结果的和,并将此结果乘2以后加上(1,0),(0,1)和(1,1)三个点,即为最终结果。
欧拉函数可以用线性筛结合其自身性质求得。
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 using namespace std; 7 const int maxn=40009; 8 int n,ans,tot=0; 9 int phi[maxn],prime[maxn]; 10 int isprime[maxn],mindiv[maxn]; 11 void eular(int n) 12 { 13 for(int i=2;i<=n;i++) 14 { 15 if(!mindiv[i]) 16 { 17 prime[++tot]=mindiv[i]=i; 18 isprime[i]=1; 19 phi[i]=i-1; 20 } 21 for(int j=1,k;j<=tot&&prime[j]<=mindiv[i]&&(k=prime[j]*i)<=n;j++) 22 { 23 mindiv[k]=prime[j]; 24 if(i%prime[j]==0) 25 { 26 phi[k]=phi[i]*prime[j]; 27 break; 28 } 29 else 30 phi[k]=phi[i]*(prime[j]-1); 31 } 32 } 33 } 34 int main() 35 { 36 scanf("%d",&n); 37 isprime[1]=0; 38 eular(maxn); 39 for(int i=1;i<=n-1;i++) 40 { 41 ans+=phi[i]; 42 } 43 cout<<ans*2+3<<endl; 44 return 0; 45 }