BZOJ2190 [SDOI2008]仪仗队(欧拉函数)

与HDU2841大同小异。

设左下角的点为(1,1),如果(1,1)->(x,y)和(1,1)->(x',y')向量平行,那只有在前面的能被看见。然后就是求x-1、y-1不互质的数对个数。

而x或y等于1可以另外讨论一下,就是当n不等于1时就有两个,n等于1就特判一下。

那么就用欧拉函数计数了:枚举x-1,累加小于x-1与x-1互质的个数,即合法的y-1的个数;结果还要*2,因为还有一半对称的y-1>x-1的情况;此外x-1=y-1多算了一次,减去1即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 #define MAXN 43210
 5 int phi[MAXN],prime[MAXN];
 6 bool vis[MAXN];
 7 void euler(){
 8     phi[1]=1;
 9     int tot=0;
10     for(int i=2; i<MAXN; ++i){
11         if(!vis[i]){
12             prime[tot++]=i;
13             phi[i]=i-1;
14         }
15         for(int j=0; j<tot; ++j){
16             if(i*prime[j]>MAXN) break;
17             vis[i*prime[j]]=1;
18             if(i%prime[j]==0){
19                 phi[i*prime[j]]=phi[i]*prime[j];
20                 break;
21             }else{
22                 phi[i*prime[j]]=phi[i]*(prime[j]-1);
23             }
24         }
25     }
26 }
27 int main(){
28     euler();
29     int n;
30     scanf("%d",&n);
31     if(n==1){
32         putchar('0');
33         return 0;
34     }
35     int res=2;
36     for(int i=2; i<=n; ++i){
37         res+=phi[i-1]<<1;
38     }
39     printf("%d",res-1);
40     return 0;
41 } 

 

你可能感兴趣的:(BZOJ2190 [SDOI2008]仪仗队(欧拉函数))