• BZOJ 1004: [HNOI2008]Cards


    传送门

    注意题目的条件: "输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代

    替"

    所以对于每种方案,只要考虑经过一次洗牌后可能变成的情况

    显然,如果有 m 种洗牌法,那么一种方案就可以被洗出 m+1 种方案

    继续考虑,如果有另一种方案不属于这 m+1 种方案

    那么它一定也可以洗出另外不重复的 m+1 种方案

    所以推广一下,如果不考虑洗牌时方案有 sum 种,那么最后答案就是 $frac{sum}{m+1}$

    然后考虑如何求 sum

    设 $n=S_r+S_b+S_g$

    红色可以在 n 张空白牌中随便选,所以有 $C^{S_r}_{n}$ 种选法

    然后考虑蓝色,因为红色已经选了,所以只能在 $n-S_r$ 中随便选,有 $C^{S_b}_{n-S_r}$ 种选

    最后绿色没得选了,只能把剩下的全染成绿色,有1种选法

    乘起来,化简一波,得到$frac{(S_r+S_b+S_g)!}{(S_r!cdot S_b!cdot S_g!)}$

    最后答案再除以 $(m+1)$ 就好了

    注意有取余,所以除要乘逆元

    直接费马小定理就好了,代码就不注释了

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    int sa,sb,sc,m,mo;
    inline int ksm(int x,int y)
    {
        int res=1;
        while(y)
        {
            if(y&1) res=res*x%mo;
            x=x*x%mo; y>>=1;
        }
        return res;
    }
    int f[107];
    int main()
    {
        sa=read(); sb=read(); sc=read(); m=read(); mo=read();
        int a;
        for(int i=1;i<=m;i++)
            for(int i=1;i<=sa+sb+sc;i++) a=read();
         f[0]=1; for(int i=1;i<=sa+sb+sc;i++) f[i]=f[i-1]*i%mo;
         printf("%d",f[sa+sb+sc]*ksm(f[sa]*f[sb]%mo*f[sc]%mo*(m+1)%mo,mo-2)%mo);
         return 0;
    }
  • 相关阅读:
    方法
    成员变量和局部变量
    带参数的方法
    包名规范
    String
    导包
    java基础(十二章)
    java基础(十一章)
    java基础(九章)
    java基础(八章)
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10103163.html
Copyright © 2020-2023  润新知