一眼卡特蘭數...寫完才發現不對勁,樣例怎麼輸出$0$...原來模數不必定是質數= =...ios
第一次見到模數不是質數的求組合數方法$(n,m\leq 10^7)$,記錄一下...ide
先對於$1$~$n$的每一個數篩出最小的質因子(我確定是寫埃式篩啦),那麼乘上一個數$x$至關於乘上$x$的全部質因子,因此從大到小掃一遍每個數,若$x$被乘了$1$次且$x$不是質數,那麼就給$x$的最小質因子$mn_x$和$\frac{x}{mn_x}$的次數+$1$,顯然這樣最後只會剩下質因子有記錄次數,那麼這個次數就是質因子的指數了。spa
若是求$C(n,m)$,不妨設$n-m\leq m$,那麼$m+1$~$n$被乘了$1$次,$1$~$n-m$被除了$1$次,也就是被乘了$-1$次,那麼這些數的質因子都應該被減去相應次數。會不會有質因子被減到負數了?咱們知道組合數必定是正整數,因此確定不會出負數啦~code
最後掃一遍全部質數,快速冪一下就能夠求得組合數了,$n$之內的質數個數是$O(\frac{n}{logn})$級別的,快速冪是$O(logn)$的,因此複雜度是$O(n)$的。blog
對於這題使用卡特蘭數的$C(2n,n)/(n+1)$的公式會比較好一些,不算$n+1$的貢獻就行了get
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=2000010, inf=1e9; int n, mod, ans; int p[maxn], mn[maxn], cnt[maxn]; bool v[maxn]; inline void read(int &k) { int f=1; k=0; char c=getchar(); while(c<'0' || c>'9') c=='-'&&(f=-1), c=getchar(); while(c<='9' && c>='0') k=k*10+c-'0', c=getchar(); k*=f; } inline void getp() { for(int i=2;i<=n<<1;i++) if(!v[i]) { p[++p[0]]=i; for(int j=i<<1;j<=n<<1;j+=i) v[j]=1, !mn[j] && (mn[j]=i); } } inline int power(int a, int b) { int ans=1; for(;b;b>>=1, a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod; return ans; } inline void add(int x, int delta) { cnt[x]+=delta; if(v[x]) { cnt[mn[x]]+=cnt[x]; cnt[x/mn[x]]+=cnt[x]; cnt[x]=0; } } int main() { read(n); read(mod); getp(); ans=1; for(int i=n<<1;i>n+1;i--) add(i, 1); for(int i=n;i>1;i--) add(i, -1); for(int i=1;i<=p[0];i++) ans=1ll*ans*power(p[i], cnt[p[i]])%mod; printf("%d\n", ans); }