zoukankan      html  css  js  c++  java
  • 数论总结

    一:扩展欧拉定理的一种更简便的写法

    void exgcd(int a,int b,int &d,int &x,int &y){
        if(b) exgcd(b, a % b, d, y, x), y -= x * (a / b);
        else x = 1, y = 0, d = a;
    }

    例:OJ 1135

    二:线性求逆元,若$a*i+b=p,a=lfloor frac{p}{i} floor,b=p%i$则$frac{1}{i}=-frac{a}{b}$

    inv[1] = 1;
    for(int i=2; i<=n; i++)
        inv[i] = p - (p / i) * inv[p % i] % p;

     三:大步小步算法,求$a^x=b(mod p)$,令$k=sqrt{p},0<c<=k,0<=d<k$,原式可转化为$a^{ck-d}=b$,即$a^{ck}=b*a^d$,用hash表保存每一个$b*a^d$,最后依次检验即可

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

    例题:洛谷 3846

    四:牛顿迭代法,令$x_0$为一个任意值,重复令$x_0=x_0-frac{f(x_0)}{f^{'}(x_0)}$,最后$x_0$会稳定在函数f的零点上,这个方法大部分情况下成立(没有固定的规律)

    例:10次循环计算根号(非常快):

    int main(){
        while(1){
            double c, x0 = 1;
            scanf("%lf", &c);
            if(!c) break;
            for(int i=1; i<=10; i++)
                x0 = (x0 + c / x0) / 2;
            printf("%.12lf
    ", x0);
        }
        return 0;
    }

     五:(巨坑)树的计数

    1:有标号无根树计数:$Ans = n^{n-2}$,可以考虑prufer序列,序列中的x的数量+1就是图中点的度数,以此来考虑问题

    2:有标号有根树计数:$Ans = n*n^{n-2}=n^{n-1}$,就是有标号无根树情况中以每个点为根,所以答案乘以n

    3:无标号有根树计数:令$f_k$为k个点的树的数量,转移方程$f_k = frac{sum_{i=1}^{k-1} f_i sum_{j|k-i} jf_j}{n-1}$

    设生成函数$F(x)=xprod_{i=1}^{infty}(frac{1}{1-x^i})^{f_i}$

    两边取对数得$lnF(x)=lnx-f_isum_{i=1}^{infty}({1-x^i})$

    两边求导得$frac{F^{'}(x)}{F(x)}=frac{1}{x}+sum_{i=1}^{infty}if_ifrac{x^{i-1}}{1-x^i}$

    化简得$xF^{'}(x)=F(x)+F(x)sum_{i=1}^{infty}frac{x^i}{1-x^i}$

    对比$x^n$系数得$nf_n=f_n+sum_{i-1}^{infty}if_isum_{j=ik,kin N^+}f_{n-j}$

    最终化简得到$f_k = frac{sum_{i=1}^{k-1} f_i sum_{j|k-i} jf_j}{n-1}$

    朴素算法时间复杂度是$O(n^2)$,但这里还有一个$O(nlog^2n)$的算法

    CDQ分治在这里又排上用场了,设$g(x)==sum{j|x}jf_j$,则$(n-1)f_n=sum_{i=1}^{n-1}f_ig_{n-i}$,这不就是卷积的形式吗

    先计算$[1,frac{n}{2}]$的f,之后每计算完成一个f就更新g,因为g(x)只与$j|x的f(j)$有关,所以$frac{n}{2}$之后的g(x)实际上已经更新完了,所以就可以直接用FFT乘法计算左边对右边的贡献,最后再计算右边之间的贡献就可以了

    4:无标号无根树计数:令这个图的重心为根,则它的子树的大小都小于$frac{n}{2}$,所以答案就是有根树数量减去子树大小大于$frac{n}{2}$的有根数的数量,注意当n为偶数时要额外减去重心有两个点的情况

    例:OJ 1301 1305

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 501, MOD = 998244353;
    int a[MAXN], C[MAXN][MAXN], Dp[MAXN][MAXN];
    
    int main(){
        int n = read();
        for(int i=0; i<=n; i++) for(int j=0; j<=i; j++)
            C[i][j] = (j == 0 || j == i) ? 1 : (C[i-1][j-1] + C[i-1][j]) % MOD;
        for(int i=1; i<=n; i++)
            a[i] = read();
        Dp[0][0] = 1;
        for(int i=1; i<=n; i++) for(int j=0; j<=n-2; j++) for(int k=0; k<=min(j,a[i]-1); k++)
            Dp[i][j] = ((long long)C[j][k] * Dp[i-1][j-k] + Dp[i][j]) % MOD;
        printf("%d", Dp[n][n-2]);
        return 0;
    }
    View Code
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    
    inline long long read(){
        long long ans = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch))
            f *= (ch == '-') ? -1 : 1, ch = getchar();
        do ans = (ans << 1) + (ans << 3) + (ch ^ 48), ch = getchar();
        while(isdigit(ch));
        return ans * f;
    }
    
    const int MAXN = 2001, MOD = 998244353;
    int Dp[MAXN], g[MAXN];
    
    int pow(int a,int x){
        int ans = 1;
        while(x){
            if(x & 1) ans = (long long)ans * a % MOD;
            a = (long long)a * a % MOD, x >>= 1;
        }
        return ans;
    }
    
    
    
    int main(){
        int n = read();
        Dp[1] = 1, g[1] = 1;
        for(int i=2; i<=n; i++){
            for(int j=1; j<i; j++)
                Dp[i] = ((long long)g[i-j] * Dp[j] + Dp[i]) % MOD;
            Dp[i] = (long long)Dp[i] * pow(i - 1, MOD - 2) % MOD;
            for(int j=1; j<=i; j++) if(i % j == 0)
                g[i] = ((long long)Dp[j] * j + g[i]) % MOD;
        }
        printf("%d", Dp[n]);
        return 0;
    }
    View Code
  • 相关阅读:
    Oracle第一课
    Web前端试题
    E
    Kingdom of Black and White
    D. Let's Go Hiking
    2021牛客寒假 第一场
    Codeforces Round #691 (Div. 2)
    CF1461D
    CF1461B
    浙财16th校赛 F因子
  • 原文地址:https://www.cnblogs.com/PHDHD/p/12596445.html
Copyright © 2011-2022 走看看