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;
}
后记
如果有下界的情况,可以考虑直接换元转化为一样的题目。

浙公网安备 33010602011771号