• 【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;
    }

     

  • 相关阅读:
    Netty实战
    ObjectTools反射实例
    SpringBoot新增监听器Listener
    拦截器(Inteceptor),过滤器(Filter),切面(Aspect)处理HttpServiceReqeust请求
    Linux CentOS7.2下安装Redis && 配置Redis开机自启动
    JVM命令行工具&垃圾收集器&垃圾收集策略思维导图
    Redis总结
    Java自定义注解的实现
    反射实例
    系统管理员常用的Linux命令
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7669895.html
Copyright © 2020-2023  润新知