[BZOJ2190][SDOI2008]仪仗队 数学

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2190

看到这道题首先想到了NOI2010的能量采集,这不就是赤裸裸的弱化版吗?直接上莫比乌斯反演就行了。

令$f(d)=\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)==d]$

则有$g(d)=\sum_{i=1}^n\sum_{j=1}^n[d|gcd(i,j)]=\frac{n}{d}\frac{n}{d}=\sum_{d|n}f(d)$

由莫比乌斯反演得$f(d)=\sum_{d|n}μ(\frac{n}{d})F(n)=\sum_{x=1}^nμ(x)\frac{n}{dx}\frac{n}{dx}$

然而并没有写,因为发现有更简单的做法。

其实我们发现除开对角线单看一半,就是求小于n的x的phi值的和是多少,根据$gcd(a,b)=1$容易观察出来,然后最后加上对角线还有x轴y轴上三个特殊的点就可以了。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 int p[40010],cnt=0;
 7 int phi[40010];
 8 bool vis[40010];
 9 void sieve(){
10     for(int i=2;i<=40000;i++){
11         if(!vis[i]){
12             p[++cnt]=i;
13             phi[i]=i-1;
14         }
15         for(int j=1;p[j]*i<=40000&&j<=cnt;j++){
16             vis[i*p[j]]=true;
17             if(i%p[j]==0){
18                 phi[i*p[j]]=phi[i]*p[j];
19                 break;
20             }
21             phi[i*p[j]]=phi[i]*(p[j]-1);
22         }
23     }
24 }
25 int N;
26 int main(){
27     sieve();
28     scanf("%d",&N);
29     ll ans=0;
30     for(int i=2;i<N;i++) ans+=phi[i];
31     ans=ans*2+3;
32     printf("%lld\n",ans);
33     return 0; 
34 }

 

posted @ 2017-10-03 21:38  halfrot  阅读(187)  评论(0编辑  收藏  举报