题意:求Catalan数的前n项和。
直接递推公式就好了,但是有一个问题,递推式里有除法,而由于除数与模数不互质,不能预处理逆元,这里有一个求不互质同余除法的方法(前提是结果必须是整数,所以只能用来求Catalan,Stirling和组合数这样的数)
$\frac{a}{b}\equiv c (mod \ d)$,我们先将d质因数分解,然后对于$a$和$b$将d的质因子部分单独统计,剩余部分直接exgcd求逆元即可。
因为剩余部分满足互质所以可以直接做逆元,而我们有$p\equiv p(mod \ ap)$,所以最后质因子部分直接乘就可以了。
这样就解决了HNOI2017的70分做法。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
using namespace std; const int maxn=100010;
typedef long long ll; ll ans,cnt[maxn];
vector<int> prime;
int n,m; void exgcd(ll a,ll b,ll &x,ll &y){
if (!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=x*(a/b);
} ll inv(ll a,ll p){ ll x,y; exgcd(a,p,x,y); return (x+p)%p; } void getPrime(){
ll t=m;
for (int i=2; i*i<=t; i++)
if (t%i==0){
prime.push_back(i);
while (t%i==0) t/=i;
}
if (t>1) prime.push_back(t);
} void solve(){
getPrime(); ans=1; ll res=1;
rep(i,2,n){
ll fz=4*i-2,fm=i+1;
for (int k=0; k<(int)prime.size(); k++)
if (fz%prime[k]==0)
while (fz%prime[k]==0) fz/=prime[k],cnt[k]++;
res=(res*fz)%m;
for (int k=0; k<(int)prime.size(); k++){
if (fm%prime[k]==0)
while (fm%prime[k]==0) fm/=prime[k],cnt[k]--;
}
if (fm>1) res=(res*inv(fm,m))%m;
ll t=res;
for (int k=0; k<(int)prime.size(); k++)
rep(s,1,cnt[k]) t=(t*prime[k])%m;
ans=(ans+t)%m;
}
printf("%lld\n",ans);
} int main(){
while(~scanf("%d%d",&n,&m) && n+m)
prime.clear(),memset(cnt,0,sizeof(cnt)),solve();
return 0;
}