把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF451E Devu and Flowers 分析

题目概述

\(n\) 个非负整数 \(x_i\),所有的 \(x_i\leq a_i\),求当 \(\sum_{i=1}^n x_i=s\) 的方案。

分析

这是一道模板题。

对于没有限制的直接插板 \(C_{s+n-1}^{n-1}\)

现在考虑有限制,直接容斥,其中 \(S=\{1,2,3,\dots,n\}\)

\[ans=\sum_{T\subseteq S}(-1)^{|T|}\times C_{s-\sum_{j\in T}(a_j+1)+n-1}^{n-1} \]

然后就这样做就行了。

为什么是 \(a_j+1\) 呢,因为我们钦定他为这个值,其溢出的值分给其他的,所以是至少 \(T\) 这些位置上的数溢出了。

其中组合数直接乘就行了,因为最多是 \(\mathcal{O}(n)\) 的。

代码

时间复杂度 \(\mathcal{O}(n2^n)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#define int long long
#define N 25
using namespace std;
int popcount(int x) {
    int res = 0;
    for (;x;x -= x & -x) res ++;
    return res;
}
const int mod = 1e9 + 7;
int qpow(int a,int b) {
    int res = 1;
    while(b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
int C(int a,int b) {
    if (a < 0 || b < 0 || a < b) return 0;
    int fz = 1;
    for (int i = a;i > a - b;i --) fz = fz * (i % mod) % mod;
    int fm = 1;
    for (int i = 1;i <= b;i ++) fm = fm * i % mod;
    return fz * qpow(fm,mod - 2) % mod;
}
int n,a[N],s;
signed main(){
    cin >> n >> s;
    for (int i = 1;i <= n;i ++) scanf("%lld",&a[i]);
    int ans = 0,t = (1 << n);
    for (int i = 0;i < t;i ++) {
        int xs = popcount(i);
        int sum = 0;
        for (int j = 1;j <= n;j ++)
            if ((i >> j - 1) & 1) sum += a[j] + 1;
        xs = ((xs & 1) ? -1 : 1);
        ans = (ans + (xs * C(s - sum + n - 1,n - 1) % mod + mod) % mod) % mod;
    }
    cout << ans;
    return 0;
}

后记

如果有下界的情况,可以考虑直接换元转化为一样的题目。

posted @ 2025-10-19 20:45  high_skyy  阅读(2)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end