密码解锁

密码解锁

给出一个数列\(\{a_i\}\),限定上界n,对于任意一个位置i,i的Mobius函数值,等于i的倍数的位置上的值,t组询问,给出m,求第m个位置上的值。

不难看出为数论问题,现在关键在于建模,于是不不难有

\[a_m+a_{2m}+...+a_{[n/m]m}=\mu(m) \]

\[\mu(m)=\sum_{m|d}^na_d \]

由Mobius反演定理,我们有

\[a_m=\sum_{m|d}^n\mu(d)\mu(d/m)=\sum_{d=1}^{[n/d]}\mu(dm)\mu(d)=\sum_{d=1}^{[n/d]}\mu^2(d)\mu(m)(gcd(d,m)==1) \]

\(\sum_{i=1}^n\mu^2(i)\)联想容斥原理,采取更改容斥范围的办法解决问题,设\(N=[n/m]\),于是有

\[a_m=\sum_{d=1}^{\sqrt{N}}\mu(d)\sum_{d^2|e}^N(gcd(e,m)==1)= \]

\[\sum_{d=1}^{\sqrt{N}}\mu(d)\sum_{e=1}^{[N/d^2]}(gcd(ed^2,m)==1) \]

因为\(d^2\)的存在不好反演,考虑提出特判

\[a_m=\sum_{d=1}^{\sqrt{N}}\mu(d)(gcd(d,m)==1)\sum_{e=1}^{[N/d^2]}(gcd(e,m)==1)= \]

\[\sum_{d=1}^{\sqrt{N}}\mu(d)(gcd(d,m)==1)\sum_{e=1}^{[N/d^2]}\sum_{x|e,x|m}\mu(x)= \]

\[\sum_{d=1}^{\sqrt{N}}\mu(d)(gcd(d,m)==1)\sum_{x|m}\mu(x)[\frac{N}{d^2e}] \]

容易知道m的约数个数是固定的,于是考虑单独处理出其\(\mu\)值,接下直接枚举式子,不难得知时间复杂度应为\(O(\sqrt{N}log_2^N+\sqrt{N}\sigma(m))=O(\sqrt{N}\sigma(m))\)

参考代码:

#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
#define swap(x,y) x^=y^=x^=y
using namespace std;
bool check[50001];
int prime[10000],pt,mu[50001],
    ys[2000],ym[2000],yt;
il int Mu(ll);
template<class free>
il void read(free&);
il void prepare(int);
il ll gcd(ll,ll);
int main(){
    int lsy;read(lsy),prepare(50000);
    ll n,m,i,j,ans1,ans2;
    while(lsy--){
        read(n),read(m);
        n/=m,yt&=0,ans1&=0;
        for(i=1;i*i<m;++i)
            if(!(m%i))
                ys[++yt]=i,ym[yt]=Mu(i),
                    ys[++yt]=m/i,ym[yt]=Mu(m/i);
        if(i*i==m)ys[++yt]=i,ym[yt]=Mu(i);
        for(i=1;i*i<=n;++i){
            ans2&=0;
            if(gcd(i,m)==1)
                for(j=1;j<=yt;++j)
                    ans2+=ym[j]*(n/(i*i)/ys[j]);
            ans1+=ans2*mu[i];
        }printf("%lld\n",ans1*Mu(m));
    }
    return 0;
}
il ll gcd(ll a,ll b){
    while(b)swap(a,b),b%=a;return a;
}
il int Mu(ll n){
    ll i;int tot(0);
    for(i=2;i*i<=n;++i)
        if(!(n%i)){
            n/=i;if(!(n%i))return 0;
            ++tot;
        }if(n>1)++tot;
    return (tot&1)?-1:1;
}
il void prepare(int n){
    ri int i,j;mu[1]=1;
    for(i=2;i<=n;++i){
        if(!check[i])prime[++pt]=i,mu[i]=-1;
        for(j=1;j<=pt&&prime[j]*i<=n;++j){
            check[i*prime[j]]|=true;
            if(!(i%prime[j]))break;
            mu[i*prime[j]]=~mu[i]+1;
        }
    }
}
template<class free>
il void read(free &x){
    x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

posted @ 2019-05-18 09:18  a1b3c7d9  阅读(154)  评论(0编辑  收藏  举报