zoukankan      html  css  js  c++  java
  • HDU-3240(卡特兰数+分解质因数后求逆元)

    卡特兰数相关公式 :

    1. (H_n = {C_{2n}^n over n+1)})
    2. (H_n = {(4n-2)over n+1} imes H_{n-1})
    3. (H_n = C_{2n}^n - C_{2n}^{n-1})
    4. $ H_n = egin{cases} sum_{i=1}^{n} H_{i-1} H_{n-i} & n geq 2, n in mathbf{N_{+}} 1 & n = 0, 1 end{cases} $

    因为 (nle 100000) ,所以不考虑第四种,第一种和第三种种求组合数也不可以用递推来求,而用公式的话因为要预先算出阶乘和阶乘的逆元,在此题中m不保证为质数,所以也不好计算。

    对于第三种,假设以及算出了(H_{n-1}) 那么只需要求出({4n-2over n+1}) 即可

    先把 m 分解质因数,然后对于分子 (4n-2) ,求出m分解后的质因子的所有指数,然后对于分母(n+1) ,也求出m分解的质因子的所有指数,前后两个指数数组相减。剩下分子和分母与m互质的部分直接求即可,保留到递推答案pre中。

    综上,当前递推的答案由一个变量pre 和一个指数数组共同记录,所以在地推出当前答案之后进行累加时,还要用pre乘所有质因子

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1000010;
    typedef long long ll;
    int n,m;
    int cnt[N];
    vector<ll> v;
    void exgcd(ll a,ll b,ll& d,ll& x,ll& y) {
        if(!b) {
            d = a; x = 1; y = 0;
        }else{
            exgcd(b,a%b,d,y,x); y -= x*(a/b);
        }
    }
    ll inv(ll a,ll n){
        ll d,x,y;
        exgcd(a,n,d,x,y);
        return d== 1?(x+n)%n:-1;
    }
    void getPrime(int x){
        for(int i=2;i*i<=x;i++){
            if(x % i)continue;
            while(x%i==0)x/=i;
            v.push_back(i);
        }
        if(x > 1)v.push_back(x);
        return;
    }
    int main(){
        while(cin >> n >> m){
            if(n == 0 && m == 0)break;
            v.clear();
            memset(cnt,0,sizeof cnt);
            ll res = 1 % m;
            ll pre = 1;
            getPrime(m);//对m进行分解质因数
            for(int i=2;i<=n;i++){
                ll fz = 4 * i - 2, fm = i + 1;
                for(int j=0;j<v.size();j++){
                    if(fz % v[j] == 0)
                    while(fz % v[j] == 0){
                        fz /= v[j];
                        cnt[j] ++;//指数++
                    }
                }
                pre = pre * fz % m;//剩余互质部分直接乘
                for(int j=0;j<v.size();j++){
                    if(fm%v[j] == 0)
                    while(fm % v[j] == 0){
                        fm /= v[j];
                        cnt[j] --;//指数--
                    }
                }
                if(fm > 1) pre = pre * inv(fm,m) % m;//更新pre
                ll tmp = pre;
                for(int j=0;j<v.size();j++){
                    for(int k=1;k<=cnt[j];k++){
                        tmp = (tmp * v[j]) % m;//计算当前答案
                    }
                }
                res = (res + tmp) % m;
            }
            cout << res << endl;
        }
        return 0;
    }
    

    为什么不是每次直接把质因子直接计算到pre中呢,因为之后的计算中,对分母(n+1)进行分解质因数时,有可能出现不够减的情况,所以我们要一直用一个数组记录这部分和m有公因数的部分

  • 相关阅读:
    docker cacti
    zabbix5.0官方部署+监控nginx+mysql
    CentOS7 Haproxy2.2.2部署示例
    LVS(DR) + keepalived
    linux备份整个系统
    docker部署OceanBase 试用版
    NextCloud开源视频会议平台
    idea使用maven proguard 对ssm项目进行代码混合详细步骤
    C# 范围运算符[1..2]
    对象是否为空的扩展方法
  • 原文地址:https://www.cnblogs.com/1625--H/p/11462589.html
Copyright © 2011-2022 走看看