• BZOJ4710 分特产


    题目链接:戳我

    容斥题。

    (f[i])表示至多有i个人能够分到(也就是至少n-i个人分不到)的方案数
    (f[i]=prod_{j=1}^mC_{a[j]+i-1}^i-1)

    a[j]表示的是该特产的数量。

    为什么组合数是那样子写的呢?大家考虑一下,a[j]个球,分成i份,每份可以为空是不是就是这样子写的呢?(当然大家也可以考虑一下如果不为空怎么写呢。。不会的话可以去看看数学选修2-3,不过当然,这个不在本题的讨论范围内啦)

    然后根据容斥原理,我们知道每个人都至少有一个特产的方案数=至少有0个人没有-至少1个人没有+至少2个人没有。。。。。(等效于上面的至多嘛)

    然后答案就是(sum_{i=1}^n(-1)^{n-i}C_n^if[i])

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define MAXN 100010
    #define mod 1000000007
    using namespace std;
    int n,m;
    int a[MAXN];
    long long ans=0;
    long long dp[MAXN],f[MAXN],C[2010][2010];
    inline void init()
    {
    	for(int i=0;i<=2000;i++) C[i][0]=1,C[i][i]=1;
    	for(int i=2;i<=2000;i++)
    		for(int j=1;j<i;j++)
    			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++)
    		scanf("%d",&a[i]);
    	init();
    	for(int i=1;i<=n;i++) f[i]=1;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=m;j++)
    			f[i]=1ll*f[i]*C[i+a[j]-1][i-1]%mod;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		int op;
    		if((n-i)&1) op=-1;
    		else op=1;
    		ans=(ans+1ll*op*C[n][i]*f[i]+mod)%mod;
    	}
    	printf("%I64d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    java 各个文件夹的含义
    对称加密 & 非对称加密
    leetcode 155 最小栈
    leetcode 53 最大自序列和
    leetcode 146 LRU 缓存机制
    notebook 开启 有限元学习
    leetcode 232 用栈实现队列
    LINUX装机问题:无法使用“Ctrl+Alt+[F1~F6]”快捷键切换到终端
    JAVA笔记4-static关键字
    C++构造函数、析构函数、虚析构函数
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10416247.html
Copyright © 2020-2023  润新知