[HNOI2009]有趣的数列,洛谷P3200,Catalan+简化公式

xiaoxiao2025-10-16  5

正题

      题目传送门

      因为所有奇数项是升序的,所以

      又因为奇数项小于偶数项

      所以每个偶数位都能插在所对应奇数项的后面,换一种说法,就是把2*n个数从小到大排好序,把奇数项和偶数项丢进去,使得每一个前缀,奇数项的个数都比偶数项多。

      求Catalan数有4个公式。(点链接查看)

      其中有两个组合数公式是在一起的。

      那么前面两种很明显不行,第一种会超时,第二种因为p不是质数,求不了逆元,而且p也没有什么很好的性质。

      那么组合数,为了简单,我们选取第一种,并且化简

      

      很明显这个东西肯定是可以整除的。

      所以,又不能求逆元,那么我们就分解质因数,然后上下抵消不就行了?

#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; int n,p; int prime[2000010],mmin[2000010]; int t[2000010]; bool vis[2000010]; long long ksm(long long x,int t){ long long tot=1; while(t>=1){ if(t%2==1){ tot*=x; tot%=p; } x*=x; x%=p; t/=2; } return tot; } int main(){ scanf("%d %d",&n,&p); for(int i=2;i<=2*n;i++){ if(vis[i]==false) prime[++prime[0]]=i,mmin[i]=i; for(int j=1;j<=prime[0] && i*prime[j]<=2*n;j++){ vis[i*prime[j]]=true; mmin[i*prime[j]]=prime[j]; if(i%prime[j]==0) break; } } int x; for(int i=n+2;i<=2*n;i++){ x=i; while(x!=1) t[mmin[x]]++,x/=mmin[x]; } for(int i=2;i<=n;i++){ x=i; while(x!=1) t[mmin[x]]--,x/=mmin[x]; } long long ans=1; for(int i=1;i<=prime[0];i++){ ans=ans*ksm((long long)prime[i],t[prime[i]])%p; } printf("%lld\n",ans); }

      

      

转载请注明原文地址: https://www.6miu.com/read-5038038.html

最新回复(0)