P3200 [HNOI2009]有趣的数列

洛谷

首先发现它是个卡特兰数

  • 硬算前几项的数字规律(我是这样做的)

  • 可以转换为一个典型的卡特兰数的例子:

    n个数排成两行,使右边都大于左边,后边都大于前边,求排法数量

    将奇数看成第一行,将偶数看成第二行即可。

这道题的卡塔兰数,困难点在于模数不是质数,所以不能用费马小定理来求逆元,所以我们需要另辟蹊径

\(C_{2n}^n\)=\(\dfrac{2n!}{n!n!}\)

\(\dfrac{C_{2n}^{n}}{n+1}=\dfrac{2n!}{n!\left( n+1\right) !}\)

其实阶乘相比,有很多项其实是可以直接约掉的,根据质因数分解定理,就可以用下面的公式约掉

temp=0;
m=2*n;
while(m>0)
{
	m=m/prime[i];
	temp=temp+m;
}
m=n+1;
while(m>0)
{
	m=m/prime[i];
	temp=temp-m;
}
m=n;
while(m>0)
{
	m=m/prime[i];
	temp=temp-m;
    
}
ans=ans*quick_pow(prime[i],temp);//注意这里是乘不是加

然后,就没了

代码

#include<bits/stdc++.h>
using namespace std;
int n,mod,m;
int cnt;
const int N=2000000;
int prime[N];
bool vis[N];
int temp;
void divide(int x)
{
	for(int i=2; i<=x; i++)
	{
		if(vis[i]==0)
		{
			prime[++cnt]=i;
		}
		for(int j=1; prime[j]<=x/i&&j<=cnt; j++)
		{
			vis[prime[j]*i]=1;
			if((i%prime[j])==0) break;
		}
	}
}

long long quick_pow(int a,int b)
{
	long long ans=1;
	while(b)
	{
		if(b&1)ans=ans*a;
		a=(long long)a*a%mod;
		b>>=1;
	}
	return ans;
}

long long res=1;
int main()
{
	cin>>n>>mod;
	divide(n*2);
	for(int i=1; i<=cnt; i++)
	{
		temp=0;
		m=2*n;
		while(m>0)
		{
			m=m/prime[i];
			temp=temp+m;
		}
		m=n+1;
		while(m>0)
		{
			m=m/prime[i];
			temp=temp-m;
		}
		m=n;
		while(m>0)
		{
			m=m/prime[i];
			temp=temp-m;
		}
		res=((long long)res*quick_pow(prime[i],temp)%mod+mod)%mod;//注意这里是乘不是加
	}
	cout<<res<<endl;
	return 0;
}
posted @ 2020-11-27 18:34  邦的轩辕  阅读(27)  评论(0编辑  收藏  举报