zoukankan      html  css  js  c++  java
  • 数论总结(下)(高级数论)

    #一.$BSGS$算法(大步小步算法) 求解:(a^xequiv bpmod{c}) 其中$c$为质数 我们把$x$拆为$x = im - j$。 那么:(a^xequiv bpmod{c}) ------->(a^{im-j}equiv bpmod{c}) (a^{im-j}equiv bpmod{c}) --------> (ba^jequiv a^{im}pmod{c}) 显然$m$取$sqrt$最舒服,那么令$m=sqrt$, 然后枚举$i$((i leq sqrt{c})),把$a^$用$map$或者$hash$存起来。 这样我们再枚举$j$,只需要检查$baj$是否已经存在即可, 假如存在,那么此时$x=im-j$即为方程的解。 代码参考:戳我! #二.卢卡斯定理(Lucas) ##1.卢卡斯定理: 就一句话: (C_n^m \% p = C_{n\% p}^{m\%p}*C_{n/p}^{m/p}) 其中**$p$为质数**,一般用于计算比较大的组合数。 ##2.扩展Lucas定理: 当**$p$不为质数**的时候,先唯一分解: (p = p_1^{k_1}*p_2^{k_2}....P_n^{k_n}) 那么其实就是求解下面这个方程组中的$ans$: (ansequiv c_1pmod{p_1^{k_1}}) (ansequiv c_2pmod{p_2^{k_2}}) (......) (ansequiv c_npmod{p_n^{k_n}}) 其中$c_1$、(c_2)(...)、$c_n$为对应$C_nm % p_t^$的答案。 假设我们可以求得$c_1$、(c_2)(...)(c_n),那么直接$CRT$一波即可得到$ans$。 所以现在问题变为求解$C_nm%pk$。 我们知道:(C_n^m = frac{n!}{m!(n-m)!}) 所以其实我们就是要求$n! % pk$。这个东西这么求呢? 首先,我们等会是要求逆元的,所以应该要先把$p$提出来,等会算完逆元后再乘回去即可。 所以我们可以把上面的$n!$拆为: (n! = p^t*lfloor frac{n}{p} floor !*G(n)) 其中$G(n)$为不是$p$倍数的数的乘积,显然$lfloor frac floor !$可以递归求解。 $pt$是提出来的最后再一起算,所以我们只要考虑如何算$G(n)$。 观察到$G(n) % pk$是以$pk$为周期的,所以肯定可以数论分块,分块搞一下即可。 最后考虑一下$pt$这一项,一个$prod_$中约数$p$的个数为$sum_{pr leq n} {lfloor frac{pr}} floor$,可以直接算出$t$。 然后就做完了,记得最后强行$CRT$一波合并$c_i$即可。 这里给出求解$C_nm%p^k$部分的代码:

    注:代码中的pk代表p^k,是事先求好了的。
    LL fac(LL n,LL p,LL pk)            //计算(n!) % (p^k)
    {
        if(n==0)return 1;
        LL res=1;
        for(LL i=2;i<=pk;i++)                 //求解G(n)中的整块:
            if(i%p)res=(res*i)%pk;                   
        res=pow(res,n/pk,pk);                //res = res^(n/(p^k)) //分块一波
        for(LL i=2;i<=n%pk;i++)                     
            if(i%p)res=(res*i)%pk;            //求解G(n)中的余项。
        return (res*fac(n/p,p,pk))%pk;        //递归求解。
    }
    LL Calc(LL n,LL m,LL p,LL pk)
    {
        if(n<m)return 0;
        LL a=fac(n,p,pk),b=fac(m,p,pk),c=fac(n-m,p,pk);
        //得到了a、b、c中的G(x)与floor(n/p)!, 因为要提出p先不算所以不求解p^t
        LL k=0;
        for(LL i=n;i;i/=p)k+=i/p;                        
        for(LL i=m;i;i/=p)k-=i/p;
        for(LL i=n-m;i;i/=p)k-=i/p;            //求解C(n,m)中质因子p的个数(t)。
        LL res=(((a*inv(b,pk))%pk)*inv(c,pk))%pk * pow(p,k,pk)%pk;
        //把质因子p(p^t)乘回来
        return res;
    }
    

    #三.提取公因数 这个其实不能算是数论吧.... 但是这里列一个专题是因为它太重要了提取公因数数论分块被称为数论两大套路(笔者自己yy不要管啦) 提取公因式衍生出来的是**“考虑每一项对答案的贡献”,一般涉及这种思想的题目都是非常难的。 其实具体还是要见题拆题。这里给两个例子: ###例子1 假如$a2-ab = E2$ , 那么如何快速求解符合条件的$(a、b)$二元组? (a^2-ab = a(a-b) = E^2),所以$a=F2$ , (a-b=S^2) 所以$F2-b = S^2$,即得到:(b = (F-S)(F+S))** 枚举量一下子就大幅度的减少了。 ###例子2 求解$sum_n sum_m gcd(i,j)$。 把$d=gcd(i,j)$给提出来。 (sum_{i=1}^n sum_{j=1}^m gcd(i,j) = sum_{d=1}^{min(n,m)}dsum_{i=1}^n sum_{j=1}^m [gcd(i,j)=d] = sum_{d=1}^{min(n,m)}dsum_{i=1}^{ lfloor frac{n}{d} floor } sum_{j=1}^{lfloor frac{m}{d} floor } [gcd(i,j)=1]) 然后至于$sum_{ lfloor frac floor } sum_{lfloor frac floor } [gcd(i,j)=1]$怎么快速求见后面的莫比乌斯反演。 ###例子3 求解$sum_n phi(d) sum{lfloor frac floor} {lfloor frac floor}$,多组数据。 令$T = id$ , 然后把$T$给提出来。 (sum_{d=1}^n phi(d) sum^{lfloor frac{n}{d} floor}_{i=1} {lfloor frac{n}{id} floor} = sum_{T = 1}^n{lfloor frac{n}{T} floor} sum_{d|T} phi(d)) 后面的$sum{d|T} phi(d)$可以线性筛,具体见后面相关内容,从而使得询问时单组复杂度由$O(n)$变为了$O(sqrt)$ #四.莫比乌斯反演((Mobius)) 当一个函数$F(n)$很好求,而其可以写成其约数或倍数$d$的函数$f(d)$,$f(d)$很不好求时, 我们可以通过莫比乌斯反演用$F(n)$反推$f(d)$,从而实现快速求解$f(d)$。 其实就是容斥原理的体现,证明见这里 戳我! 莫比乌斯反演有两种形式: ###1.约数形式: 若有$F(n) = sum_{d|n} f(d)$ 那么$$f(n) = sum_{d|n} mu(frac)*F(d)$$ ###2.倍数形式: 若有$F(n) = sum_{n|d} f(d)$ 那么$$f(n) = sum_{n|d} mu(frac)*F(d)$$ ###3.莫比乌斯函数: 莫比乌斯函数即为$mu(d)$,定义如下: (1)若$d=1$,那么$mu(d)=1$ (2)若$d=p_1p_2p_3...p_k$,$p_1,p_2...(均为互异素数,那么)mu(d)=(-1)^k$ (3)其它情况下$mu(d)=0$ 莫比乌斯函数为积性函数,可以线性筛出,下面给出代码:

    void Mobius(){
        memset(Isprime,true,sizeof(Isprime));
        mu[1] = 1; Isprime[1] = false;
        for(int i = 2; i <= n; i ++){
            if(Isprime[i]){prm[++cnt] = i; mu[i] = -1;}
            for(int j = 1; prm[j]*i<=n && j <= cnt; j ++){
                Isprime[i*prm[j]] = false;
                if(i%prm[j] == 0){mu[i*prm[j]] = 0; break;}
                else mu[i*prm[j]] = -mu[i];
            }
        }
    }
    

    ###4.莫比乌斯反演与$sum [gcd(i,j)=1]$ 求解$gcd(i,j)$相关问题是莫比乌斯反演最常见的应用。 当遇到涉及莫比乌斯反演的题目时,一般也是先把其转化为求$sum_^n sum_m [gcd(i,j)==1]$ 下面给出求解$sum_n sum_m [gcd(i,j)==1]$$(nleq m)$的莫比乌斯反演过程: 令$f(d) = sum_n sum_m [gcd(i,j)==d]$ 然后令: (F(n) = f(d)+f(2d)+...+f(kd)=sum_{n|d} f(d)) 所以$F(d)$即表示$gcd(i,j)$为$d$的倍数的二元组的个数。 那么显然$F(d)$非常好求: (F(d) = lfloor frac{n}{d} floor * lfloor frac{m}{d} floor) 又因为$F(n) = sum_{n|d} f(d)$ 所以通过莫比乌斯反演得到: (f(n) = sum_{n|d}^{d leq n} mu(frac{d}{n})F(d)) 所以: (f(1) = sum_{i=1}^{n} mu(i)F(i) = sum_{i=1}^{n} mu(i)lfloor frac{n}{i} floor * lfloor frac{m}{i} floor) 先求一下$mu(i)$的前缀和,然后数论分块就行了。 上面得到的关系式非常重要,你甚至可以把它记下来(n<=m): (sum_{i=1}^n sum_{j=1}^m [gcd(i,j)=1]=sum_{i=1}^{n} mu(i)lfloor frac{n}{i} floor * lfloor frac{m}{i} floor) ###5.莫比乌斯反演习题: 见莫比乌斯反演题目列表:[戳这里!] (http://www.cnblogs.com/GuessYCB/p/8277359.html) #五.积性函数线性筛 与 狄利克雷卷积 ##1.积性函数 与 线性筛 ###a.积性函数相关定义 (1)积性函数: 若存在函数$f(x)$ ,当$(x,y)=1$时 , 满足$f(x*y)=f(x)f(y)$,则称$f(x)$为积性函数。 (2)完全积性函数: 若对于任意$x,y$,有$f(xy) = f(x)*f(y)$,则称$f(x)$为完全积性函数。 (3)常见的积性函数: 莫比乌斯函数$mu(i)$ 、 欧拉函数$phi(i)$。 ###b.积性函数的线性筛(sieve) 完全积性函数的筛法就不讲了,直接乘起来即可。 那么对于积性函数$f(x)$的线性筛,我们要求下面几个东西有定义或很好求: (1)(f(1)) (2)(f(p)) , ($p$为质数) (3)(f(p^k)) , ($p$为质数) 其中$f(1) , f(p)$一般为$O(1)$算,$f(pk)$则一般从$f(p)$推来。 那么假设我们已经求解的上面函数的取值,考虑如何筛。 由积性函数的定义我们可以知道$f(x*y)=f(x)*f(y)(的前提条件为)(x,y)=1$。 所以当我们要筛一个$f(n)$时,我们要把$n$拆为两个互质的数$x,y$的乘积。 显然最优秀的办法就是让$x$取最小值因子,把最小质因子$xk$分离出来,这样就可以套上线性筛了。 我们记$low(i)$表示$i$的最小质因子$x$的$xk$, 那么根据线性筛的原则,我们分两种情况讨论($i,prm[j]$含义见素数线性筛): (1)当$i%prm[j] != 0$时 这太容易了不是吗,$i$与$prm[j]$互质,直接套定义即可。 (f(i*prm[j]) = f(i)*f(prm[j]);low(i*prm[j]) = prm[j]) (2)当$i%prm[j]==0$时 首先$low(i*prm[j]) = low(i)*prm[j]$这没有什么好说的吧。 然后: 第一种情况:(low(i)=i),那么$i$是$pk$形式,用特殊方法计算。 第二种情况:(low(i)!=i),那么我们把$prm[j]*i$拆为两个互素的数,具体为把$prm[j]$给除干净: (f(i*prm[j] = f(i / low[i]) * f(low[i]*prm[j])) 然后就没有了。 下面给出具体实现代码:

    void sieve(){
        low[1] = 1; f[1] = 对f(1)的特殊定义; tot = 0;
        for(int x = 2; x <= n; x ++){
            if(!Prime[x]){prm[++tot] = x; f[x] = 对f(p)的特殊定义; low[x] = x;}
            for(int j = 1; j <= tot && x*prm[j] <= n; j ++){
                Prime[x*prm[j]] = true;
                if(x%prm[j] == 0){
                    low[x*prm[j]] = low[x] * prm[j];
                    if(x == low[x])
                        f[x*prm[j]] = 对f(p^k)的特殊定义;
                    else
                        f[x*prm[j]] = f[x/low[x]] * f[prm[j]*low[x]];
                    break;
                }
                low[x*prm[j]] = prm[j];
                f[x*prm[j]] = f[x] * f[prm[j]] % mod;
            }
        }
        return;
    }
    

    ##2.狄利克雷卷积 其实懂了积性函数的线性筛之后这玩意就是来搞笑的。 对于积性函数$f(x)$与$g(x)$,它们的狄利克雷卷积也是积性函数。 其中它们的狄利克雷卷积长这样: ((f*g)(n) = sum_{d|n} f(d) g(frac{n}{d})) 狄利克雷卷积的性质: 交换律:((f*g) = (g*f)) 结合律:((f*g)*h = f*(g*h)) 狄利克雷卷积自身不难,把它当做积性函数一样的线性筛即可。 #六.杜教筛 ....还不会,到时候回来补(先去搞点其他的换脑子啦): 留下学习资料: http://blog.csdn.net/skywalkert/article/details/50500009 http://www.cnblogs.com/zhoushuyu/p/8301660.html

  • 相关阅读:
    Spring异常重试框架Spring Retry
    Ubuntu 16.04无法在WPS中输入中文的问题解决
    Ubuntu 16.04使用百度云的方案
    Ubuntu 16.04安装Wine版的迅雷+QQ(完美方案,终极解决方法)
    Ubuntu下Deb软件包相关安装与卸载
    Spring在Java Filter注入Bean为Null的问题解决
    MyBatis 3在Insert之后返回主键
    MySQL JDBC URL参数(转)
    MySQL索引原理及慢查询优化
    Markdown 语法整理大集合2017
  • 原文地址:https://www.cnblogs.com/GuessYCB/p/8268430.html
Copyright © 2011-2022 走看看