BZOJ 3027: [Ceoi2004]Sweet (容斥计数)

题意

BZOJ3027

题解

先考虑恰好吃NN个糖果的方案。由于有mimi的限制,套路地想到容斥。枚举子集哪些不满足限制,然后把NN减去所有不满足的mi+1mi+1,剩下的就插板法就行了。假设枚举的集合中的(mi+1)=tsum(mi+1)=t,答案就是:(Nt+n1n1)inom{N-t+n-1}{n-1}

然后考虑到并不是恰好NN个,而是在[a,b][a,b]的区间内,答案就是枚举NN,所有的情况加起来:i=atbt(i+n1n1)sum_{i=a-t}^{b-t}inom{i+n-1}{n-1}

发现可以写成一个前缀和相减的形式,答案就是i=0bt(i+n1n1)i=0at1(i+n1n1)sum_{i=0}^{b-t}inom{i+n-1}{n-1}-sum_{i=0}^{a-t-1}inom{i+n-1}{n-1}

所以只需要求i=0k(i+n1n1)sum_{i=0}^kinom{i+n-1}{n-1}

发现这个可以O(1)O(1)求:i=0k(i+n1n1)=(k+nn)sum_{i=0}^kinom{i+n-1}{n-1}=inom{k+n}{n}

所以就做完了…吗?

还有求组合数的问题。模数是合数,不能直接lucas。可以使用分解质因数再CRT合并,但比较麻烦。有一种方法就是这样:

  • 因为有abmod  m=amod  bmbfrac{a}{b}mod m=frac{amod bm}{b}
  • 所以有(nm)=i=1m(ni+1)m!mod  2004=i=1m(ni+1)mod  2004m!m!inom nm=frac{prod_{i=1}^{m}(n-i+1)}{m!}mod 2004=frac{prod_{i=1}^{m}(n-i+1)mod2004cdot m!}{m!}

这道题组合数只求(kn)inom{k}{n},而nn范围是10le10,所以200410!2004*10!longlonglonglong范围内,直接存下来模就行了。

具体见代码

CODE

#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 2004;
const int MAXN = 2005;
LL facn = 1;
inline int C(int n, int m) {
	LL re = 1;
	for(int i = 1; i <= m; ++i)
		re = re * (n-i+1) % (facn*mod);
	return re / facn;
}
int n, m[15], sgn[(1<<10)+5];
inline int calc(int k) { return C(k+n, n); }
int main () {
	int a, b, ans = 0;
	scanf("%d%d%d", &n, &a, &b);
	for(int i = 0; i < n; ++i) {
		scanf("%d", &m[i]);
		facn *= i+1;
	}
	sgn[0] = 1;
	for(int s = 0; s < (1<<n); ++s) {
		if(s&1) sgn[s] = -sgn[s>>1];
		else sgn[s] = sgn[s>>1];
		int t = 0;
		for(int i = 0; i < n; ++i)
			if(s&(1<<i)) t += m[i]+1;
		
		int B = max(b-t, -1), A = max(a-t, 0);
		if(A <= B) ans = (ans + 1ll * sgn[s] * (calc(B) - calc(A-1)) % mod) % mod;
	}
	printf("%d
", (ans + mod) % mod);
}
原文地址:https://www.cnblogs.com/Orz-IE/p/12039229.html