zoukankan      html  css  js  c++  java
  • 【BZOJ4665】小w的喜糖 容斥+组合数

    【BZOJ4665】小w的喜糖

    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

    题解:显然我们应该将每种糖果放在一起处理,用v[i]表示有多少人有第i种糖果。然后考虑容斥,用f[i][j]表示前i种糖果,至多j个人的糖果与原来不同的方案数,然后很容易DP求出f数组。

    $f[i][j]=sumlimits_{k=0}^{v[i]}f[i-1][j-k]*C_{v[i]}^{k}*(v[i])*(v[i]-1)*...*(v[i]-k+1)$

    发现我们在DP过程中并没有考虑我们选出来那j个人的顺序,所以最后f[i][j]乘上j!即可。最后因为每个糖果是相同的,所以方案数要除以v[i]!。

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const ll P=1000000009;
    int n,m;
    ll ans;
    int col[2010],s[2010],v[2010];
    ll c[2010][2010],f[2010][2010],jc[2010],ine[2010],jcc[2010];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd();
    	int i,j,k;
    	for(i=0;i<=n;i++)
    	{
    		c[i][0]=1;
    		for(j=1;j<=i;j++)	c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
    	}
    	jc[0]=ine[0]=jcc[0]=jc[1]=ine[1]=jcc[1]=1;
    	for(i=2;i<=n;i++)
    	{
    		jc[i]=jc[i-1]*i%P,ine[i]=P-(P/i)*ine[P%i]%P,jcc[i]=jcc[i-1]*ine[i]%P;
    	}
    	for(i=1;i<=n;i++)	col[i]=rd();
    	sort(col+1,col+n+1);
    	for(i=1;i<=n;i++)
    	{
    		if(col[i]>col[i-1])	m++;
    		v[m]++;
    	}
    	for(i=1;i<=m;i++)	s[i]=s[i-1]+v[i];
    	f[0][0]=1;
    	for(i=1;i<=m;i++)	for(j=0;j<=s[i-1];j++)	for(k=0;k<=v[i];k++)
    		f[i][j+k]=(f[i][j+k]+f[i-1][j]*c[v[i]][k]%P*jc[v[i]]%P*jcc[v[i]-k]%P)%P;
    	for(i=0;i<=n;i++)
    	{
    		ans=(ans+((i&1)?-1:1)*f[m][i]*jc[n-i]+P)%P;
    	}
    	for(i=1;i<=m;i++)	ans=ans*jcc[v[i]]%P;
    	printf("%lld",ans);
    	return 0;
    }

     

  • 相关阅读:
    Redis源代码分析(十三)--- redis-benchmark性能測试
    kvm中运行kvm
    umount.nfs device busy day virsh extend diskSpace, attachDisk
    ultravnc
    openNebula dubug
    maintenance ShellScripts
    virsh VMI deploy data serial xml
    cloud computing platform,virtual authentication encryption
    基于C 的libvirt 接口调用
    storage theory
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7669895.html
Copyright © 2011-2022 走看看