zoukankan      html  css  js  c++  java
  • bzoj4665 小w的喜糖(dp+容斥)

    4665: 小w的喜糖

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 222  Solved: 130
    [Submit][Status][Discuss]

    Description

    废话不多说,反正小w要发喜糖啦!!
    小w一共买了n块喜糖,发给了n个人,每个喜糖有一个种类。这时,小w突发奇想,如果这n个人相互交换手中的糖,那会有多少种方案使得每个人手中的糖的种类都与原来不同。
    两个方案不同当且仅当,存在一个人,他手中的糖的种类在两个方案中不一样。

    Input

    第一行,一个整数n
    接下来n行,每行一个整数,第i个整数Ai表示开始时第i个人手中的糖的种类
    对于所有数据,1≤Ai≤k,k<=N,N<=2000

    Output

    一行,一个整数Ans,表示方案数模1000000009

    Sample Input

    6
    1
    1
    2
    2
    3
    3

    Sample Output

    10

    首先我们把每颗糖(第i种糖有$A_i$个)都看成不同的(也就是同种糖的排列顺序不同也算进方案)

    最后再$ans/=A_i!$,这样就可以忽略同种糖的问题

    一般看到这种题,都是先套路地求至少有$i$个......的方案数,再用容斥求答案。本题也是如此

    我们套路地设$f[i][j]$为前$i$种糖,至少$j$个人不合法的方案数

    $f[i][j]=sum_{k=0}^{min(j,A_i)} f[i-1][j-k]*C(A_i,k)*A_i!/(A_i-k)!$

    对于每个$f[n][i]$,剩下的$n-i$个人可以随意分糖

    所以最终方案数$F[i]=f[n][i]*(n-i)!$

    但是肯定有重复算的鸭

    所以搞搞容斥统计下就好辣

    $ans=sum_{i=0}^n(-1)^iF[i]$

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    #define N 2005
    const ll P=1e9+9;
    int n,A[N];
    ll f[N][N],inv[N],fac[N],ifac[N],ans;
    void prep(){
        inv[1]=1; fac[0]=fac[1]=ifac[0]=ifac[1]=1;
        for(ll i=2;i<=n;++i){
            inv[i]=(P-P/i)*inv[P%i]%P;
            fac[i]=fac[i-1]*i%P;
            ifac[i]=ifac[i-1]*inv[i]%P;
        }
    }
    inline ll C(int a,int b){return fac[a]*ifac[b]%P*ifac[a-b]%P;}
    int main(){
        scanf("%d",&n); prep();
        for(int i=1,q;i<=n;++i) scanf("%d",&q),++A[q];
        f[0][0]=1;
        for(int i=1;i<=n;++i)
            for(int j=0;j<=n;++j)
                for(int k=0;k<=min(j,A[i]);++k)
                    f[i][j]=(f[i][j]+f[i-1][j-k]*C(A[i],k)%P*fac[A[i]]%P*ifac[A[i]-k]%P)%P;
        for(int i=0;i<=n;++i) ans=((ans+1ll*((i&1)?-1:1)*f[n][i]*fac[n-i]%P)%P+P)%P;
        for(int i=1;i<=n;++i) if(A[i]>0) ans=ans*ifac[A[i]]%P;
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    最小路径和
    S2 深入.NET和C#编程 机试测试错题积累
    S2 深入.NET和C#编程 笔试测试错题积累
    影院项目的内容信息
    抽象类和抽象的方法注意事项
    六种设计原则
    体检套餐的笔记
    C#图解 类和继承
    深入类的方法
    S2 深入.NET和C#编程 三:使用集合组织相关数据
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10789511.html
Copyright © 2011-2022 走看看