zoukankan      html  css  js  c++  java
  • CF 451E Devu and Flowers

    可重集的排列数 + 容斥原理

    对于 ({A_1 * C_1, A _2 * C_2, cdots, A_n * C_n})这样的集合来说,
    (N = sum_{i = 1} ^ n A_i), 要在这个集合中取出 (M) 个元素来,这样的方案数是:

    [C _ {N+M-1}^{N-1} - sum _ {i =1} ^ n {C_{N+M-A_i - 2}^{N-1}} + sum _ {1leq i < j leq n} ^ n {C_{N+M - A_i - A_j -3}^{N-1}} cdots +(-1)^N * C_{N+M-sum_{i = 1}^n {c_i} - (N+1)}^{N-1} ]

    我们可以通过枚举 (1 sim 2 ^ N - 1)的数来表示这些组合数,对于一个数 (x) 来说,如果它的第 (p) 位上是 1 ,就表示减去 (A_p) ,若一共有 (q) 位是 1 ,则 一共减去 (q) 个元素,
    在计算组合数 (C_M^N) 的时候,我们可以先计算 (A_M^N), 在乘上 ((N- 1)!)的逆元.

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    using namespace std;
    const int MOD = 1000000007;
    ll n, inv[100];
    ll num[50], m, ans;
    ll C(ll x, ll y) {
    	if(x < 0 || y < 0 || x < y) return 0;
    	x %= MOD;
    	if(!y) return 1;
    	if(!x) return 0;
    	ll ans = 1ll;
    	for(int i = 0; i < y; i++) {
    		(ans *= (x - i) ) %= MOD;
    	}
    	(ans *= inv[y] ) %= MOD;
    	return ans;
    }
    int main() {
    	inv[0] = inv[1] = 1;
    	for(int i = 2; i <= 30; i++) inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
    	for(int i = 2; i <= 30; i++) (inv[i] *= inv[i - 1]) %= MOD;
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) cin >> num[i];
    	ans += C(m + n - 1, n - 1);
    	for(int i = 1; i < (1 << n); i++) {
    		ll t = m + n;
    		int p = 0;
    		for(int j = 0; j < n; j++) {
    			if((i >> j) & 1) {
    				p++;
    				t -= num[j + 1];
    			}
    		}
    		t -= p + 1;
    		if(p & 1) {
    			(ans -= C(t, n - 1)) %= MOD;
    		}else (ans += C(t, n - 1)) %= MOD;
    	}
    	cout << (ans + MOD) % MOD << endl;
    	return 0;
    }
    
  • 相关阅读:
    5、流程控制
    4、字典和元祖
    3、列表操作
    2、字符串和数据类型
    1.标识符练习
    使用xpath提取页面所有a标签的href属性值
    网页提取所有邮箱
    正则表达式
    提取包含QQ的文本为QQ邮箱
    python继承小demo
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/8653725.html
Copyright © 2011-2022 走看看