HDU-3240(卡特兰数+分解质因数后求逆元)
Posted 1625--h
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU-3240(卡特兰数+分解质因数后求逆元)相关的知识,希望对你有一定的参考价值。
卡特兰数相关公式 :
- \(H_n = C_2n^n \over n+1)\)
- \(H_n = (4n-2)\over n+1\times H_n-1\)
- \(H_n = C_2n^n - C_2n^n-1\)
- $ H_n = \begincases \sum_i=1^n H_i-1 H_n-i & n \geq 2, n \in \mathbfN_+\ 1 & n = 0, 1 \endcases $
因为 \(n\le 100000\) ,所以不考虑第四种,第一种和第三种种求组合数也不可以用递推来求,而用公式的话因为要预先算出阶乘和阶乘的逆元,在此题中m不保证为质数,所以也不好计算。
对于第三种,假设以及算出了\(H_n-1\) 那么只需要求出\(4n-2\over 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有公因数的部分
以上是关于HDU-3240(卡特兰数+分解质因数后求逆元)的主要内容,如果未能解决你的问题,请参考以下文章