HDU3240題解

分析:一看就知道是卡特蘭數
卡特蘭數的公式:
令h(0)=1,h(1)=1,catalan數滿足遞推式[1] :

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)h(0) (n>=2)

例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2

h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5

另類遞推式[2] :

h(n)=h(n-1)*(4*n-2)/(n+1);

遞推關係的解爲:

h(n)=C(2n,n)/(n+1) (n=0,1,2,…)

遞推關係的另類解爲:

h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,…)

這道題目用到了第二個遞推式,賽場上記不到也沒問題 記住形狀
h[n] = h[n-1] * (a * n - b) / (n + c) abc枚舉一下就出來了。

這題難點還是求逆元,因爲有分母取模,而且m和i+1不一定互質。
所以分開考慮,因素分解m,然後得到m的素因子 記入map中,每次分解i+1的時候,判斷這個因子是不是在map中出現過就行了。出現過記錄,沒出現過的部分就是和m互質的部分直接相乘取模就行了

//
//  Created by Matrix on 2015-12-20
//  Copyright (c) 2015 Matrix. All rights reserved.
//
//
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e5 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;

ll extended_gcd(ll a, ll b, ll &x, ll &y, ll& mod) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    else {
        ll gcd = extended_gcd(b, a % b, x, y, mod);
        ll t = x % mod;
        x = y % mod;
        y = ((t - a/b*x) % mod + mod) % mod;
        return gcd;
    }
}
ll num[maxn];
map <ll, ll> mp, vis;
map <ll, ll>::iterator iter;
ll fac[maxn], top;
void DivNum(ll n) {
    top = 0;
    for(ll i = 2; i * i <= n; i++) {
        if(n % i == 0) {
            fac[top] = i;
            num[top] = 0;
            while(n % i == 0) {
                n /= i;
                num[top]++;
            }
            top++;
        }
    }
    if(n != 1) {
        fac[top] = n;
        num[top++] = 1;
    }
}
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
//  dp[0] = dp[1] = 1;
//  for(int i = 2; i <= 1e5; i++) {
//      dp[i] = dp[i-1] * (4 * i - 2) / (i + 1);
//  }
    ll n, m;
    while(scanf("%lld%lld", &n, &m) != EOF && (n + m)) {
        if(m == 1) {puts("0"); continue;}
        mp.clear();
        vis.clear();
        ll st = 1 % m;
        ll ans = st;
        DivNum(m);
        for(int i = 0; i < top; i++) {
            vis[fac[i]]++;
        }
        for(ll i = 2; i <= n; i++) {
            ll u = i * 4 - 2;
            ll d = i + 1;
            DivNum(u);
            for(int j = 0; j < top; j++) {
                if(vis.count(fac[j])) {
                    while(num[j]) {
                        u /= fac[j];
                        num[j]--;
                        mp[fac[j]]++;
                    }
                }
            }
            DivNum(d);
            for(int j = 0; j < top; j++) {
                if(vis.count(fac[j])) {
                    while(num[j]) {
                        d /= fac[j];
                        num[j]--;
                        mp[fac[j]]--;
                    }
                    if(mp[fac[j]] == 0) mp.erase(fac[j]);
                }
            }
            ll x, y;
            extended_gcd(d, m, x, y, m);
            st = st * u % m * x % m;
            ll tmp = st;
            for(iter = mp.begin(); iter != mp.end(); iter++) {
                ll p = iter -> second;
                ll ss = 1;
                while(p--) {
                    ss = ss * (iter -> first) % m;
                }
                tmp = tmp * ss % m;
            }
//          printf("st = %lld\n", tmp);
            ans = (ans + tmp) % m;
        }
        cout << ans << endl;
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章