• 记一些数学引理和结论等


    @

    一些结论

    (gcd(x^a-1,x^b-1)=x^{gcd(a,b)}-1)
    (gcd(fib[x],fib[y])=fib[gcd(x,y)])


    费马大定理

    定理:(a^n+b^n=c^n;;(nge3时没有整数解))
    扩展:当(a=2*k+1)为奇数时,(c=k^2+(k+1)^2,b=c-1);当(a=2*k)为偶数时,(c=k^2+1,b=c-2)


    第二类斯特林数

    (S(n,k))一个(n)元集的所有(k)划分的个数。(n)个不同的球放到(k)个同样的盒子使无空盒。
    定理1:(S(n+1,k)=S(n,k-1)+k imes S(n,k))
    定理2:(S(n,2)=2^{n-1}-1,S(n,n-1)=C_2^n)
    定理3:(S(n+1,k)=C_{k-1}^nS(k-1,k-1)+C_{k}^nS(k,k-1)+...+C_{n}^nS(n,k-1))


    整数的无序拆分

    (B(n,k)=0,;n<k)
    (B(n,1)=B(n,n)=1)
    (H(n)=B(n,1)+B(n,2)+...+B(n,n))
    定理1:(B(n+k,k)=B(n,1)+B(n,2)+...+B(n,k))

    • 解法1:记忆化搜索(复杂度接近(O(n^2)))

    (dfs(n, m)) 表示用(1-m)的数字无序分解(n)的方案数。

    1.当(n==m)时:你可以选择用(n)分解得到(1)个方案,加上不用(n)分解的方案(dfs(n,m-1))
    2.当(n>m)时:你可以选择用(m)分解得到方案(dfs(n-m,m)),加上不用(m)分解的方案(dfs(n,m-1))
    3.当(n<m)时:就等于(dfs(n,n))

    当然把记忆化搜索改成递推也很好写,常数可能小点???

    const int mod = 1e9 + 7;
    const int MXN = 1e4 + 7;
    int n;
    LL dp[MXN][MXN];
    LL dfs(int n, int m) {//用1-m的数字无序分解n的方案数
        if(n == 1 || m == 1) return 1;
        if(dp[n][m] != -1) return dp[n][m];
        LL ans = 0;
        if(n == m) ans = dfs(n, m-1) + 1;
        if(n < m) ans = dfs(n, n);
        if(n > m) ans = dfs(n, m-1) + dfs(n-m, m);
        ans %= mod;
        dp[n][m] = ans;
        return ans;
    }
    int main(int argc, char const *argv[]){
        scanf("%d", &n);
        memset(dp, -1, sizeof(dp));
        printf("%lld
    ", dfs(n, n));
        memset(dp, -1, sizeof(dp));
        for(int i = 1; i <= n; ++i) dp[i][1] = 1, dp[1][i] = 1;
        for(int i = 2; i <= n; ++i) {
            for(int j = 2; j <= n; ++j) {
                if(i == j) dp[i][j] = (dp[i][j-1] + 1)%mod;
                else if(i > j) dp[i][j] = (dp[i][j-1] + dp[i-j][j])%mod;
                else dp[i][j] = dp[i][i];
            }
        }
        printf("%lld
    ", dp[n][n]);
        return 0;
    }
    
    • 解法2:母函数法之暴力解多项式乘法

    (G(x)=(x^0+x^1+...+x^n) imes (x^0+x^2+x^4+...+x^{2 imes frac n2}) imes ... imes(x^0+x^{n imes frac nn}))
    用两个数组迭代暴力求解。
    母函数法应该还可以优化吧?

    const int mod = 1e9 + 7;
    const int MXN = 1e5 + 7;
    int n;
    LL n1[MXN], n2[MXN], v[MXN];
    LL a[MXN], b[MXN];
    void init(int n) {
        for(int i = 1; i <= n; ++i) {
            n1[i] = 0; n2[i] = n/i; v[i] = i;
            b[i] = 1; a[i] = 0;
        }
        b[0] = 1;
    }
    void solve(int n) {
        for(int i = 2; i <= n; ++i) {
            memcpy(a, b, sizeof(LL)*(n+2));
            memset(b, 0, sizeof(LL)*(n+2));
            for(int j = n1[i]; j <= n2[i] && j*v[i] <= n; ++j) {
                for(int k = 0; k+j*v[i] <= n; ++k) {
                    b[k+j*v[i]] = (b[k+j*v[i]]+a[k])%mod;
                }
            }
        }
        printf("%lld
    ", b[n]);
    }
    int main(int argc, char const *argv[]){
        scanf("%d", &n);
        init(n);
        solve(n);
        return 0;
    }
    

    再贴一个母函数的暴力模板:

    int n;
    LL n1[MXN], n2[MXN], v[MXN];
    LL a[MXN], b[MXN];
    int last;
    void init(int n) {
        for(int i = 1; i <= n; ++i) {
            n1[i] = 0; n2[i] = n/i; v[i] = i;
            b[i] = 0; a[i] = 0;
        }
        b[0] = 1;
        last = 0;
    }
    void solve(int n) {
        for(int i = 1; i <= n; ++i) {
            int last2 = min((LL)n, last+n2[i]*v[i]);
            memcpy(a, b, sizeof(LL)*(last2+2));
            memset(b, 0, sizeof(LL)*(last2+2));
            for(int j = n1[i]; j <= n2[i] && j*v[i] <= last2; ++j) {
                for(int k = 0; k <= last && k+j*v[i] <= last2; ++k) {
                    b[k+j*v[i]] = (b[k+j*v[i]]+a[k])%mod;
                }
            }
            last = last2;
        }
        printf("%lld
    ", b[n]);
    }
    int main(int argc, char const *argv[]){
        scanf("%d", &n);init(n);solve(n);
        return 0;
    }
    

    输出无序拆分的解:
    在这里插入图片描述

    #include <stdio.h>
    //使用一个数组记录在递归过程中产生的前面需要重复输出的值
    int set[100];
    //用于在递归过程中判断是否递归到最深处,输出回车
    int k;
    //此函数表示使用不大于m的整数对n进行拆分的情况,i用于表示set数组已经存在的记录数长度
    void q(int n,int m,int i){
    	if(n==k&&n!=m){ 
    		//此时递归栈已经退回到某一分支的最上层,输出回车
    		//并重置计数器i为0
    		printf("
    ");
    		i=0;
    	}
    	if(n==1){
    		//当n为1,意味者着只能表示1
    		printf("1 ");
    		return;
    	}
    	else if(m==1){
    		//当m为1,意味着要输出n个m相加
    		for(int i=0; i<n-1; i++)
    			printf("1+");
    		printf("1 ");
    		return;
    	}
    	if(n<m) {
    		q(n,n,i);
    	}
    	if(n==m){
    		//当n等于m时,到达本次递归求和的一个叶子,此时需要输出多一个空格,表示下一次输出为另一个叶子
    		printf("%d ",n);
    		//在递归输出另一个叶子之前,将之前记录的在叶子之上的数一并输出,如上图示过程1
    		for(int j=0; j<i; j++)
    			printf("%d+",set[j]);
    		q(n,m-1,i);
    		
    	}
    	if(n>m){
    		//如果n大于m,使用m作为分解,则要首先输出m+的形式
    		printf("%d+",m);
    		//记录下作为树干节点m的值并使i自增
    		set[i++]=m;
    		//递归输出m+以后的分解
    		q(n-m,m,i);
    		//递归完毕后需要将数组记录后退一个,回到上一个节点,如上图示过程2
    		i--;
    		//执行另一个分支,在下一次递归之前输出记录的数据,如上图示过程3
    		for(int j=0; j<i; j++)
    			printf("%d+",set[j]);
    		//递归输出另一分支情况
    		q(n,m-1,i);
    	}
    }
    int main(){
    	int n;
    	while(scanf("%d",&n)!=EOF){
    		if(n<=0){
    			printf("Please input a positive interger.
    
    ");
    			continue;
    		}
    		k=n;
    		q(n,n,0);
    		printf("
    
    ");
    	}
    	return 0;
    }
    


    伯努利数模板

    (B_0=1,B_1=-frac 12,B_2=frac 16,B_3=0,B_4=-frac 1{30})
    (B_5=0,B_6=frac1{42},B_7=0,B_8=-frac1{30},B_9=0)
    nlog(n)

    //day7 J oeis
    //n%4==0和n=1时Bnl[n]是负的
    //a(n) = abs[c(2*n-1)] where c(n)= 2^(n+1) * (1-2^(n+1)) * Ber(n+1)/(n+1)
    #include<bits/stdc++.h>
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    namespace BNL{
        using namespace std;
        typedef long long LL;
        const int N = 300020;
        //const LL P = 50000000001507329LL; //190734863287 * 2 ^ 18 + 1 G = 3 常数巨大
        //const int P = 1004535809; //479 * 2 ^ 21 + 1 G = 3
        const int P = 998244353; // 119 * 2 ^ 23 + 1 G = 3
        //const int P = 104857601;  // 25 * 2 ^ 22 + 1 G = 3
        //const int P = 167772161; // 5 * 2 ^ 25 + 1 G = 3
        const int G = 3;
        int wn[25];
        LL mul(LL x, LL y) {return (x * y - (LL)(x / (long double)P * y + 1e-3) * P + P) % P;}
        int qpow(LL a, int b, int p) {
            LL res = 1;
            for(;b;b>>=1,a=a*a%p) {
                if(b&1) res=res*a%p;
            }
            return (int)res;
        }
        void getwn() {
            for(int i = 1; i <= 21; ++i) {
                int t = 1 << i;
                wn[i] = qpow(G, (P - 1) / t, P);
            }
        }
        void change(int *y, int len) {
            for(int i = 1, j = len / 2; i < len - 1; ++i) {
                if(i < j) swap(y[i], y[j]);
                int k = len / 2;
                while(j >= k) {
                    j -= k;k /= 2;
                }
                j += k;
            }
        }
        void NTT(int *y, int len, int on) {
            change(y, len);
            int id = 0;
            for(int h = 2; h <= len; h <<= 1) {
                ++id;
                for(int j = 0; j < len; j += h) {
                    int w = 1;
                    for(int k = j; k < j + h / 2; ++k) {
                        int u = y[k];
                        int t = 1LL * y[k+h/2] * w % P;
                        y[k] = u + t;
                        if(y[k] >= P) y[k] -= P;
                        y[k+h/2] = u - t + P;
                        if(y[k+h/2] >= P) y[k+h/2] -= P;
                        w = 1LL * w * wn[id] % P;
                    }
                }
            }
            if(on == -1) {
                for(int i = 1; i < len / 2; ++i) swap(y[i], y[len-i]);
                int inv = qpow(len, P - 2, P);
                for(int i = 0; i < len; ++i)
                    y[i] = 1LL * y[i] * inv % P;
            }
        }
        int tmp[N];
        void get_inv(int A[], int A0[], int t) {
            if(t == 1) {
                A0[0] = qpow(A[0], P - 2, P);
                return;
            }
            get_inv(A, A0, t / 2);
            for(int i = 0; i < t; ++i) tmp[i] = A[i];
            for(int i = t; i < 2 * t; ++i) tmp[i] = 0;
            for(int i = t / 2; i < 2 * t; ++i) A0[i] = 0;
            NTT(tmp, 2 * t, 1);
            NTT(A0, 2 * t, 1);
            for(int i = 0; i < 2 * t; ++i) {
                tmp[i] = (2 - 1LL * tmp[i] * A0[i] % P) % P;
                if(tmp[i] < 0) tmp[i] += P;
                A0[i] = 1LL * A0[i] * tmp[i] % P;
            }
            NTT(A0, 2 * t, -1);
        }
        int B[N], f[N], nf[N], a[N];
        void init() {
            f[0] = 1;
            for(int i = 1; i < N; ++i) f[i] = 1LL * f[i-1] * i % P;
            nf[N-1] = qpow(f[N-1], P - 2, P);
            for(int i = N - 2; i >= 0; --i) {
                nf[i] = 1LL * nf[i+1] * (i + 1) % P;
            }
            for(int i = 0; i < N - 1; ++i) a[i] = nf[i+1];
            int len = 1 << 17;
            get_inv(a, B, len);
            for(int i = 0; i < len; ++i) B[i] = 1LL * B[i] * f[i] % P;
        }
        void solve_bnl() {
            getwn();//最前面
            init();
        }
    }
    int main() {
        BNL::solve_bnl();
        printf("%d
    ", BNL::B[2]);
        return 0;
    }
    

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    namespace POLY{
        const int MAXN = 262144;
        const int MOD = 998244353, ROOT = 3;
        typedef vector<int> Poly;
        inline int add(int a, int b){ return (a + b) % MOD; }
        inline int sub(int a, int b){ return (a - b + MOD) % MOD; }
        inline int mul(int a, int b){ return (long long)a * b % MOD; }
        int power(int a, int b){
            int ret = 1;
            for (int t = a; b; b >>= 1){
                if (b & 1)ret = mul(ret, t);
                t = mul(t, t);
            }
            return ret;
        }
        int pow2(int n){
            int ret = 1;
            while (ret < n)ret *= 2;
            return ret;
        }
        void clean(Poly& p){
            while (!p.empty() && !p.back())p.pop_back();
        }
        Poly cut(const Poly& p, int n){
            return Poly(p.begin(), p.begin() + n);
        }
        Poly expand(const Poly& p, int n){
            Poly ret(n);
            copy(p.begin(), p.end(), ret.begin());
            return ret;
        }
        Poly operator + (Poly p, const Poly& p2){
            p.resize(max(p.size(), p2.size()));
            for (int i = 0; i < (int)p2.size(); i++)
                p[i] = add(p[i], p2[i]);
            return p;
        }
        Poly operator - (Poly p, const Poly& p2){
            p.resize(max(p.size(), p2.size()));
            for (int i = 0; i < (int)p2.size(); i++)
                p[i] = sub(p[i], p2[i]);
            return p;
        }
        Poly operator * (Poly p, int x){
            for (int i = 0; i < (int)p.size(); i++)
                p[i] = mul(p[i], x);
            return p;
        }
        void dot(Poly& p, const Poly& p2){
            for (int i = 0; i < (int)p.size(); i++)
                p[i] = mul(p[i], p2[i]);
        }
        void fft(Poly& a, bool rev){
            static int g[MAXN + 1], w[MAXN] ;
            if (!g[0]){
                w[0] = 1;
                g[0] = 1; g[1] = power(ROOT, (MOD - 1) / MAXN);
                for (int i = 2; i < MAXN; i++)
                    g[i] = mul(g[i - 1], g[1]);
            }
            int len = a.size(), d = MAXN / len;
            for (int i = 1, j = len / 2; i < len; i++){
                w[i] = g[d * (rev ? len - i : i)];
                if (i < j) swap(a[i], a[j]);
                for (int k = len; j < k; k >>= 1, j ^= k);
            }
            for (int s = 1; s < len; s <<= 1){
                int step = len / s / 2;
                for (int j = 0; j < len; j += 2 * s){
                    for (int k = j, wk = 0; k < j + s; k++, wk += step){
                        int t = mul(w[wk], a[k + s]);
                        a[k + s] = sub(a[k], t); a[k] = add(a[k], t);
                    }
                }
            }
            if (rev){
                int t = MOD / len; t = mul(t, t * len);
                for (int i = 0; i < len; i++)
                    a[i] = mul(a[i], t);
            }
        }
        Poly operator * (const Poly& p1, const Poly& p2){
            if (p1.empty() || p2.empty())return Poly();
            int len = pow2(p1.size() + p2.size());
            Poly p3 = expand(p1, len), p4 = expand(p2, len);
            fft(p3, 0); fft(p4, 0);
            dot(p3, p4); fft(p3, 1);
            p3.resize(p1.size() + p2.size() - 1);
            return p3;
        }
        Poly inv(const Poly& p){
            int len = 2 * pow2(p.size());
            Poly a, b(len), exa = expand(p, len);
            b[0] = power(p[0], MOD - 2);
            for (int i = 4; i <= len; i *= 2){
                a = cut(exa, i / 2);
                a.resize(i); b.resize(i);
                fft(a, 0); fft(b, 0); dot(a, b);
                dot(b, Poly(i, 2) - a);
                fft(b, 1); b.resize(i / 2);
            }
            b.resize(p.size());
            return b;
        }
        int fact[MAXN], factInv[MAXN];
        void init(){
            fact[0] = 1;
            for (int i = 1; i < MAXN; i++)
                fact[i] = mul(fact[i - 1], i);
            factInv[MAXN - 1] = power(fact[MAXN - 1], MOD - 2);
            for (int i = MAXN - 1; i; i--)
                factInv[i - 1] = mul(factInv[i], i);
        }
        Poly bernoulli(int n){//MAXN是n的至少两倍
            Poly p(n + 1);
            for (int i = 0; i <= n; i++)
                p[i] = factInv[i + 1];
            return inv(p);
        }
        vector<int> Bnl;
        const int maxn = 2e5 + 7;
        int jie[maxn];
        void solve_bnl() {
            jie[1] = jie[0] = 1;
            for(int i = 2; i < maxn; ++i) jie[i] = 1LL*jie[i-1]*i%MOD;
            init();
            Bnl = bernoulli(100010);
            for(int i = 0; i < 100010; ++i) Bnl[i]=Bnl[i]*1LL*jie[i]%MOD;
        }
    }
    int main() {
        POLY::solve_bnl();
        printf("%d
    ", POLY::Bnl[2]);
        return 0;
    }
    
  • 相关阅读:
    找回感觉的练习
    Java住房公积金管理系统---长春工业大学期末实训
    11.6_Filter
    11.5_Listener
    11.4_Ajax & Jquery
    11.3_MVC设计模式
    11.2_数据库连接池&DBUtils
    11.1_事物
    10.7_JSP & EL & JSTL
    10.6_Cookie&Session
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/10458775.html
Copyright © 2020-2023  润新知