DestinHistoire

 

BZOJ-2190 [SDOI2008]仪仗队(莫比乌斯反演)

题目描述

  在一个平面直角坐标系的以 \((0,0)\) 为左下角、\((n,n)(1\leq n\leq 40000)\) 为右上角的矩形中,除了 \((0,0)\) 之外,每个坐标上都插着一个钉子。

  求在原点向四周看去,能够看到多少个钉子。一个钉子能被看到,当且仅当连接它和原点的线段上没有其他钉子。

分析

  答案为 两个坐标轴一个面 两部分(两个坐标轴对答案的贡献为 \(2\))。

\[ans=2+\sum_{i=1}^{n-1}\sum_{j=1}^{n-1}[\gcd(i,j)=1] \]

  则:

\[\begin{aligned}&\sum_{i=1}^{n}\sum_{j=1}^{n}[\gcd(i,j)=1]\\ =&\sum_{i=1}^{n}\sum_{j=1}^{n}\sum_{d\mid \gcd(i,j)}\mu(d)\\ =&\sum_{d=1}^{n}\mu(d)\sum_{i=1}^{n}\sum_{j=1}^{n}[d\mid\gcd(i,j)]\\ =&\sum_{d=1}^{n}\mu(d)\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor \frac{n}{d}\rfloor} 1\\ =&\sum_{d=1}^{n}\mu(d)\Big\lfloor\frac{n}{d}\Big\rfloor^2 \end{aligned} \]

  时间复杂度 \(O(\sqrt{n})\)

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
bool vis[maxn];
long long n,cnt,prime[maxn],mu[maxn],sum[maxn];
void init()
{
    mu[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(!vis[i])
        {
            prime[++cnt]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=cnt&&i*prime[j]<maxn;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
            else
                mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<maxn;i++)
        sum[i]=sum[i-1]+mu[i];
}
long long solve(long long n)
{
    long long ans=2;
    for(long long l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        ans=ans+(sum[r]-sum[l-1])*(n/l)*(n/l);
    }
    return ans;
}
int main()
{
    init();
    int n;
    cin>>n;
    cout<<solve(n-1)<<endl;
    return 0;
}

posted on 2020-11-14 17:59  DestinHistoire  阅读(88)  评论(0)    收藏  举报

导航