zoukankan      html  css  js  c++  java
  • 【BZOJ】1485: [HNOI2009]有趣的数列

    【算法】Catalan数

    【题解】

    学了卡特兰数就会啦>_<!

    因为奇偶各自递增,所以确定了奇偶各自的数字后排列唯一。

    那么就是给2n个数分奇偶了,是不是有点像入栈出栈序呢。

    将做偶数标为-1,做奇数标为+1,显然当偶数多于奇数时不合法,因为它压不住后面的奇数。

    然后其实这种题目,打表就可知啦……QAQ

    然后问题就是求1/(n+1)*C(2n,n)%p了,p不一定是素数。

    参考bzoj礼物的解法。

    看到网上清一色的素数筛+分解质因数解法,思考了好久,感觉写了假的礼物……

    后来试了一下发现礼物的做法慢得多,原因应该是礼物解法复杂度O(min(n,P))而且常数大,分解质因数O(n),但我觉得也带常数呀?

    很奇怪……不过反正n太大只能用礼物的做法,不大的话分解质因数应该更快。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    /*------------------------------------------------------------*/
    const int inf=0x3f3f3f3f,maxn=3000010;
    
    ll n,P,m,p[200],pc[200],M[200],a[200];
    ll num,fac[maxn];
    ll power(ll x,ll k,ll p)
    {
        ll ans=1;
        while(k>0)
        {
            if(k&1)ans=ans*x%p;
            x=x*x%p;
            k>>=1;
        }
        return ans;
    }
    void exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b){x=1;y=0;return;}
        else {exgcd(b,a%b,y,x);y-=x*(a/b);}
    }
    ll inv(ll x,ll p)
    {
        ll xx,yy;
        exgcd(x,p,xx,yy);
        return ((xx%p)+p)%p;
    }
    ll calc(ll x,ll p,ll pc)
    {
        if(x<p)return fac[x];
        num+=x/p;
        return fac[x%pc]*power(fac[pc-1],x/pc,pc)%pc*calc(x/p,p,pc)%pc;
    }
    ll work(ll p,ll pc)
    {
        fac[0]=1;
        for(ll i=1;i<min(pc,2*n+10);i++)fac[i]=fac[i-1]*(i%p==0?1:i)%pc;
        num=0;
        ll n1=calc(2*n,p,pc);
        ll tmp=num;
        for(ll i=1;i<min(pc,2*n+10);i++)fac[i]=fac[i-1]*(i%p==0?1:inv(i,pc))%pc;
        num=0;
        ll n2=calc(n,p,pc)*calc(n,p,pc)%pc;
        ll np=n+1;
        while(np%p==0){num++;np/=p;}
        n2=n2*inv(np,pc)%pc;
        return n1*n2*power(p,tmp-num,pc)%pc;
    }
        
    int main()
    {
        scanf("%lld%lld",&n,&P);
        m=0;ll nowP=P;
        for(ll i=2;i*i<=nowP&&nowP>1;i++)
        {
            if(nowP%i==0){p[++m]=i;pc[m]=1;}
            while(nowP%i==0){pc[m]*=i;nowP/=i;}    
        }
        if(nowP>1){p[++m]=nowP;pc[m]=nowP;}
        ll ans=0;
        for(ll i=1;i<=m;i++)
        {
            M[i]=P/pc[i];
            a[i]=work(p[i],pc[i]);
            ans=(ans+a[i]*M[i]%P*inv(M[i],pc[i])%P)%P;
        }
        printf("%lld",(ans%P+P)%P);//答案一定要记得取非负
        return 0;
    }
    礼物的做法
  • 相关阅读:
    计算机网络 基础 1
    JAVA 基础之 多线程
    HashMap 多线程处理之 FailFast机制:
    Struts2
    JAVA 由浅及深之 Servlet
    Servlet 会话技术 , Session 及 Cookie 详解
    JAVA 设计模式 : 单例模式
    JAVA 基础之 序列化 Serializable
    代理模式 及 实现AOP 拦截机制
    web.xml 文件详解 及 listener、 filter、servlet 加载顺序
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7215075.html
Copyright © 2011-2022 走看看