• 莫比乌斯反演


    http://www.bilibili.com/video/av14325327/

    懒得听我bb的可以去看视频 这位大爷讲的太好辣orz

    我突然意识到我一个还挣扎在NOIP一等奖线上的弱鸡竟然突然学会了

    赶紧码着别忘了。。。

    一、莫比乌斯反演是什么

    如果有两个定义在Z+上的函数F(x)和G(x)满足

    则根据这个式子我们可以发现一些性质    如下图:

    所以以后我们遇到计算G(x)不好算(或者更实际一点,直接算就TLE)的时候,我们可以考虑先计算F(x)   用F(x)来计算G(x)

    所以我们要对上面那个式子进行一下变形

    观察表格的规律  直观的来讲变形后式子应该形如

    其中μ(x)是我们强行定义的一个函数  当然并不是我们定义的 是前人定义的  所以它正式的名字叫做莫比乌斯函数

    然后我们做一下换元 令T=x/d

    就可以让最后μ函数中不含x 最后的表达式为

    (并非严谨证明    详细过程可见百度百科http://baike.baidu.com/link?url=gpiZ99LcvuK_Vf7K4KszIWRgmmRQkcIpyir9IgzBkyaA3FgVCAG7mouZNVzkZgqyYWdNYUpIwFOixrM6fc8fb_#3 )

    现在  我们研究的重点就跑到了这个μ(d)上面

    到目前为止  我们掌握的性质就只有由观察得到的:μ(d)的值域为{-1,0,1}(当然严谨数学证明依然见百度百科)

    如:

    μ(1) = 1

    μ(2) = -1

    μ(3) = -1

    μ(4) = 0

    μ(5) = -1

    μ(6) = 1

    (上述6个莫比乌斯函数的取值是由表格得到的)

    我很想给出莫比乌斯函数的定义 但是我一个前MO选手现NOIP选手自己都看不懂

    所以只能给一个通俗的解释

    (1) d = 1时,μ(d) = 1

    (2) d = p1 × p2 × … × pk ,(其中p1,p2..pk是互不相同的质数) 则μ(d) = (-1)^k (-1的k次方)

    (3) 其余情况 μ(d) = 0

    根据定义 莫比乌斯函数显然有一个很重要的性质

    莫比乌斯函数是积性函数

    即对于任何的a,b∈Z+

    有μ(ab)=μ(a)μ(b)

    具体证明。。。代入就好了吧

    由此引入我们的下一个板块

    二、怎么求莫比乌斯函数

    根据莫比乌斯函数的积性和它与素数间的关系

    我们可以用线性筛求素数的方法来求莫比乌斯函数

    bool vis[MAXN];
    int primes[MAXN];
    int miu[MAXN];
    int tot;
    int getmiu(int lim)
    {
        miu[1]=1;
        for(int i=2;i<=lim;i++)
        {
            if(!vis[i])
            {
                primes[tot++]=i;
                miu[i]=-1;
            }
            for(int j=0;j<tot;j++)
            {
                int k=i*primes[j];   
                if(k>lim)break;
                vis[k]=true;
                if(i%primes[j])         //i不是primes[j]的整数倍时,i*primes[j]就不会包含相同质因子.
                    miu[k]=-miu[i];     //此时根据其积性函数的特性得 miu[k]=miu[i]*miu[primes[j]],因为primes[j]是质数,miu值为-1
                else break;                
            }
        }
    }
    重点的地方已经打了注释

    很短  压一下行也就10行  于是大家会产生疑惑  就是下一个板块——

    三、莫比乌斯函数在OI中的应用

    由于很多很难的数学题推导过程写得比代码还长

    我们这里先看一道入门题BZOJ2440

    题意:求第k个没有完全平方因子(此处1不算完全平方数)的数

    k的范围是10^9

    分析:有人说答案应该小于2*k  那这道题就是一个很裸的二分了

    二分判定的时候要判“小于等于mid且无完全平方因子的数的个数”

    判断的时候  我们可以发现“没有完全平方因子”的意思其实是“所有质因数的指数全为奇”

    于是题目变为 求小于等于mid的质因数指数都为1的数的个数

    容斥原理搞一下答案就是n-奇数个质数的平方的倍数的个数+偶数个质数的平方的倍数的个数

    也就是

    (显然i如果大于根号n并不存在)

    要说还有什么值得注意的地方 就是这题爆longlong 要用unsigned longlong

    还有就是数据太大 我们的线性筛用不了 只能采用普通筛法

    /**************************************************************
        Problem: 2440
        User: Ez3real
        Language: C++
        Result: Accepted
        Time:4192 ms
        Memory:2068 kb
    ****************************************************************/
     
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    #include<queue>
    using namespace std;
    #define LL unsigned long long
    const int Max=100010;
    const LL INF=2e16+7;
     
    LL mou[Max];
    void init()
    {
        for(LL i=2; i<Max; i++)
        {
            if(!mou[i])
            {
                mou[i]=i;
                for(LL j=i*i; j<Max; j+=i)
                    mou[j]=i;
            }
        }
        mou[1]=1;
        for(int i=2; i<Max; i++)
        {
            if(i/mou[i]%mou[i]==0) mou[i]=0;
            else mou[i]=-mou[i/mou[i]];
        }
    }
    int k;
    LL getnum(LL middle)
    {
        LL ans=0;
        for(LL i=1; i*i<=middle; i++)
        {
            ans+=mou[i]*(middle/(i*i));
        }
        return ans;
    }
    int main()
    {
        init();
        int t;
        cin>>t;
        while(t--)
        {
            scanf("%d",&k);
            LL left=1,right=INF;
            while(left<=right)
            {
                int middle=(left+right)/2;
                if(getnum(middle)<k)
                    left=middle+1;
                else
                    right=middle-1;
            }
            cout<<left<<'
    ';
        }
        return 0;
    }
    View Code

    未完待续

  • 相关阅读:
    C++总结
    KMP算法
    理解I/O Completion Port(完成端口)
    [转载]Windows网络编程系列教程之四:Select模型
    [转载]理解 I/O Completion Port (IOCP完成端口)
    [转载]IOCP模型的总结
    发个IOCP的C++例子
    说说网络通信模型
    几个网络模型的示例代码(BlockingModel、OverlappedModel、WSAEventSelect、CompletionRoutine)..c++
    关于Socket 多线程 的一篇好文章
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/7789138.html
Copyright © 2020-2023  润新知