2190: [SDOI2008]仪仗队
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2689 Solved: 1713
[Submit][Status][Discuss]
Description
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。 现在,C君希望你告诉他队伍整齐时能看到的学生人数。
Input
共一个数N。
Output
共一个数,即C君应看到的学生人数。
Sample Input
4
Sample Output
9
HINT
【数据规模和约定】 对于 100% 的数据,1 ≤ N ≤ 40000
Source
分析:
问题可以转化为求Σ(1<=i<=n) Σ(1<=j<=n) [gcd(i,j)==1]
显然如果存在一个点(i*d,j*d),那么它一定已经被(i,j)覆盖掉了...
根据Dirichlet卷积:e(i)=1 (if n=1)
0 (else)
e=μ×1,(f×g)(n)=Σ(d|n) f(d)*g(n/d)
我们可以把复杂度从n^2lgn化简为O(n)
Σ(1<=i<=n) Σ(1<=j<=n) [gcd(i,j)==1]
=Σ(1<=i<=n) Σ(1<=j<=n) e(gcd(i,j))
=Σ(1<=i<=n) Σ(1<=j<=n) Σ(d|gcd(i,j)) μ(d)
=Σ(1<=d<=n) μ(d)*(n/d)*(n/d)
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 using namespace std; 7 //大鹏一日同风起,扶摇直上九万里 8 9 const int maxn=40000+5; 10 11 int n,ans,cnt,miu[maxn],prime[maxn],vis[maxn]; 12 13 signed main(void){ 14 ans=cnt=0; 15 scanf("%d",&n);miu[1]=1;n--; 16 memset(vis,0,sizeof(vis)); 17 for(int i=2;i<=n;i++){ 18 if(!vis[i]) 19 prime[++cnt]=i,miu[i]=-1; 20 for(int j=1;j<=cnt&&prime[j]*i<=n;j++){ 21 vis[i*prime[j]]=1,miu[i*prime[j]]=-miu[i]; 22 if(i%prime[j]==0){ 23 miu[i*prime[j]]=0;break; 24 } 25 } 26 } 27 for(int i=1;i<=n;i++) 28 ans+=miu[i]*(n/i)*(n/i); 29 printf("%d ",ans+2); 30 return 0; 31 }
by NeighThorn