HYSBZ/BZOJ 1004 [HNOI2008] Cards - 组合数学

题目描述

分析:

输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代替,且对每种洗牌法,都存在一种洗牌法使得能回到原状态。

这句话是说:
(1). m种洗牌方式保证能把所有排列的变换出来,且每种洗牌方式仅且仅用一次就够了,即不用多种洗牌方式叠加使用。
(2). 对于一个排列A,通过m种不同的变换可以得到(m+1)种不同的排列(包含A本身),而且,这(m+1)种排列能且只能由这(m+1)种排列通过变换得到。

Solution 1参考 by Liu Junhao:

在n张牌中一定要有Sr张red,Sb张blue,Sg张green
方案总数记为S

S=C(Sr,n)C(Sb,nSr)C(Sg,nSrSb)

=C(Sr,n)C(Sb,nSr)C(Sg,Sg)

=C(Sr,n)C(Sb,nSr)

由于其中(m+1)种算同一种,
ans=Sm+1modp

注意题目给出:p是质数,m+1< p => gcd(m+1,p)=1
由费马小定理可得:
(m+1)p11(modp)

即 m+1的乘法逆元为
(m+1)p2

可以做了。

#include<cstdio>
int Sr,Sb,Sg,m,p,n,ans;
int mypow(int x,int k)
{
    int ret=1;
    x%=p;
    while(k){
        if(k&1)
            ret=ret*x%p;
        x=x*x%p;
        k>>=1;
    }
    return ret;
}
int main()
{
    scanf("%d%d%d%d%d",&Sr,&Sb,&Sg,&m,&p);
    n=Sr+Sb+Sg;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&ans);
    long long t=1;
    for(int i=1;i<=Sr;i++)
        t=t*(n-i+1)/i;
    ans=t%p;
    n-=Sr;
    t=1;
    for(int i=1;i<=Sb;i++)
        t=t*(n-i+1)/i;
    ans=ans*(t%p)%p;
    ans=ans*mypow(m+1,p-2)%p;
    printf("%d\n",ans);
}

Solution 2:

题解让用 置换 ,要用到Burnside引理,还要用到dp,仍然要用到乘法逆元。而且,没看懂。。。。。。。。。

posted @ 2016-02-02 16:30  KatarinaYuan  阅读(146)  评论(0编辑  收藏  举报