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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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  mp, vis;
map ::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;
}

你可能感兴趣的:(数学)