[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 }