题目大意:一个n个数的序列a,每个数范围是0~m,要求∑2ai的二进制中1的数个不超过w,有多少中方案?方案的权值之和(∑∏vai)是多少?
题目描述
给定整数 n,m,k,和一个长度为 m+1 的正整数数组 v0,v1,…,vm。
对于一个长度为 n,下标从 1 开始且每个元素均不超过 m 的非负整数序列 {ai},我们定义它的权值为 va1×va2×⋯×van。
当这样的序列 {ai} 满足整数 S=2a1+2a2+⋯+2an 的二进制表示中 1 的个数不超过 k 时,我们认为 {ai} 是一个合法序列。
计算所有合法序列 {ai} 的权值和对 998244353 取模的结果。
输入输出格式
输入格式
输入第一行是三个整数 n,m,k。
第二行 m+1 个整数,分别是 v0,v1,…,vm。
输出格式
输入输出样例
输入样例 #1
5 1 1
2 1
输出样例 #1
40
输入样例 #2
见附件中的 sequence/sequence2.in
输出样例 #2
见附件中的 sequence/sequence2.ans
说明
**【样例解释 #1】**
由于 k=1,而且由 n≤S≤n×2m 知道 5≤S≤10,合法的 S 只有一种可能:S=8,这要求 a 中必须有 2 个 0 和 3 个 1,于是有 \binom{5}{2} = 10 种可能的序列,每种序列的贡献都是 v_0^2 v_1^3 = 4,权值和为 10 \times 4 = 40。
**【数据范围】**
对所有测试点保证 1 \leq k \leq n \leq 30,0 \leq m \leq 100,1 \leq v_i < 998244353。
| 测试点 | n | k | m |
| :———-: | :—: | :——: | :—-: |
| 1 \sim 4 | =8 | \leq n | =9 |
| 5 \sim 7 | =30 | \leq n | =7 |
| 8 \sim 10 | =30 | \leq n | =12 |
| 11 \sim 13 | =30 | =1 | =100 |
| 14 \sim 15 | =5 | \leq n | =50 |
| 16 | =15 | \leq n | =100 |
| 17 \sim 18 | =30 | \leq n | =30 |
| 19 \sim 20 | =30 | \leq n | =100 |
解题思路
数据范围比较小,爆搜可以骗分。
方案一:暴力枚举序列中的每个数字,时间复杂度O(n^m),排列存在大量重复,也不太好优化。
方案二:暴力枚举每个二进制位有多少个,时间复杂度O(m^n),重复可以用组合数学优化。
程序实现
方案一优化后时间复杂度:O(n*n*2^m*m),50分。
爆搜后记忆化即可:填到序列第k个数,当前的和为x,后面剩下数字一样、需要凑的1也一样,算过可以直接返回答案。
方案二优化后时间复杂度:O(m*n^4),满分。
首先,预处理组合数c[i][j]表示C_i^j,预处理权值次幂s[i][j]表示选j个i次幂的乘积,然后进行爆搜与记忆化。
逐个格子填入数量,并一边爆搜一般记录低位1的数量、高位1的数量。
技巧1:从低次幂开始爆搜,所以后面高次幂的1对前面低次幂没有影响。
技巧2:高次幂的1只需要记录最低位的即可,因为拆来拆去都是等价的。由于高次幂的1由低次幂凑成,所以数量不超过n。
记忆化:填到2^k的数量时,低位1确定,高位1也确定(相当于数字的值确定,因为后面只受高位1影响),剩下的幂的数量也确定,下次搜到同样状态时,可以时间返回之前计算的答案,避免重复搜索。
加乘原理:后面有很多中方案,增加一个数后,这个数需要乘以后面每一种方案的权值;我们可以先将后面的方案权值之和求出来,后面直接乘即可。
组合数学:剩下的幂有n-u个,当前的幂选择i个,存放的位置有c[n-u][i]个,每一种权值之和都有那么多中方案。
递归结束条件:填完了但数量不对返回零;序列a足够n个了,只要满足条件就是一种合法方案。
(感谢mekoszc提供考场代码)