bzoj1485: [HNOI2009]有趣的數列(Catalan數)

  一眼卡特蘭數...寫完才發現不對勁,樣例怎麼輸出$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);
}
View Code
相關文章
相關標籤/搜索