题目截图

题目翻译

题目分析
正难则反,考虑所有不符合的例子
 由于n很小,所以可以状态压缩二进制遍历完全部不符合例子的组合
 对于不符合的例子,假设其中第i个不符合,那么就消耗掉fi + 1个球
 以此类推,减剩下s2个球
 这时候使用隔板法分给n个箱子,加上n - 1个挡板,就是comb(s2 + n - 1, n - 1)
 对于容斥原理,奇偶个数要对应不同的符号,这里需要注意
go代码
// LUOGU_RID: 159342370
package main
import (
	. "fmt"
	"io"
	"math/bits"
	"os"
)
// https://space.bilibili.com/206214
func cf451E(in io.Reader, out io.Writer) {
	const mod = 1_000_000_007
	pow := func(x, n int) int {
		res := 1
		for ; n > 0; n /= 2 {
			if n%2 > 0 {
				res = res * x % mod
			}
			x = x * x % mod
		}
		return res
	}
	comb := func(n, k int) int {
		if n < k {
			return 0
		}
		n %= mod
		p, q := 1, 1
		for i := 1; i <= k; i++ {
			p = p * (n - i + 1) % mod
			q = q * i % mod
		}
		return p * pow(q, mod-2) % mod
	}
	var n, s, tot, ans int
	Fscan(in, &n, &s)
	a := make([]int, n)
	for i := range a {
		Fscan(in, &a[i])
		tot += a[i]
	}
	if tot < s {
		Fprint(out, 0)
		return
	}
	for i := uint(0); i < 1<<n; i++ { // 表示这个组合中为1的盒子是超过ai个的(违法)
		s2 := s
		for j, v := range a {
			if i>>j&1 > 0 {
				s2 -= v + 1 // 现分配ai+1个
			}
		}
		res := comb(s2+n-1, n-1)     // n-1个挡板表示分成n组,剩下s2个球
		if bits.OnesCount(i)%2 > 0 { // 根据个数确定正负号, 容斥原理
			res = -res
		}
		ans += res
	}
	Fprint(out, (ans%mod+mod)%mod)
}
func main() { cf451E(os.Stdin, os.Stdout) }
 
快速幂以及组合数的go模版
const mod = 1_000_000_007
pow := func(x, n int) int {
	res := 1
	for ; n > 0; n /= 2 {
		if n%2 > 0 {
			res = res * x % mod
		}
		x = x * x % mod
	}
	return res
}
comb := func(n, k int) int {
	if n < k {
		return 0
	}
	n %= mod
	p, q := 1, 1
	for i := 1; i <= k; i++ {
		p = p * (n - i + 1) % mod
		q = q * i % mod
	}
	return p * pow(q, mod-2) % mod
}
 
总结
容斥原理的应用(根据个数,符号交替)



















