《灵茶八题》题目列表
仅仅是几个字的区别,会导致截然不同的做法,也许这就是算法之美吧!
题单合集
- 子数组 +w+
- 子数组 ^w^
- 子数组 ^w+
- 子数组 +w^
- 子序列 +w+
- 子序列 ^w^
- 子序列 ^w+
- 子序列 +w^
题解
注:下标从
贡献法
考虑
- 子数组 +w+ 子数组元素和的元素和:包含
a[i] 的子数组的左端点有i+1 个,右端点有n-i 个,根据乘法原理,有(i+1)\cdot(n-i) 个子数组包含a[i] ,所以a[i] 对答案的贡献为(i+1)\cdot(n-i)\cdot a[i] 。 - 子数组 ^w^ 子数组异或和的异或和:同上。更强的结论是:
- 当
n 是偶数时,i+1 和n-i 必定一奇一偶,所以(i+1)(n-i) 是偶数,答案为0 。 - 当
n 是奇数时,如果i 为奇数,那么i+1 和n-i 都是偶数;如果i 为偶数,那么i+1 和n-i 都是奇数,所以只有i 为偶数时(i+1)(n-i) 才是奇数。所以,答案为所有偶数下标的a[i] 的异或和。
- 当
- 子序列 +w+ 子序列的元素和的元素和:包含
a[i] 的子序列有2^{n-1} 个。所以a[i] 对答案的贡献为2^{n-1}\cdot a[i] 。所以答案为2^{n-1}\cdot \sum a[i] 。 - 子序列 ^w^ 子序列的异或和的异或和:
- 当
n=1 时,答案为a[0] 。 - 当
n\ge 2 时,由于2^{n-1} 是偶数,所以答案为0 。
- 当
二进制拆位
- 子数组 ^w+ 子数组异或和的元素和:
- 提示:如果数组中只有
0 和1 ,要怎么做? - 相当于计算有多少个子数组,异或和等于
1 。 - 计算前缀异或和数组
s (长为n+1 ),相当于从s 中选两个数,异或等于1 。 - 这两个数必须恰好一个是
1 ,另一个是0 。 - 假设
s 中有c 个1 ,那么就有n+1-c 个0 ,所以答案为c\cdot(n+1-c) 。 - 一般地,统计
s 中第k 位的1 的个数c ,那么这一位对答案的贡献是c\cdot(n+1-c)\cdot 2^k 。
- 提示:如果数组中只有
- 子序列 ^w+ 子序列异或和的元素和:
- 如果第
k 位都是0 ,那么对答案的贡献是0 。 - 如果第
k 位有c 个1 ,用数学归纳法可以证明,从c 个数中选偶数个数的方案数是2^{c-1} ,选奇数个数的方案数也是2^{c-1} 。再算上0 ,那么异或和为0 的子序列有2^{n-1} 个,异或和为1 的子序列也有2^{n-1} 个,所以这一位的贡献是2^{n-1}\cdot 2^k 。
- 如果第
0-1 背包
- 子序列 +w^ 子序列元素和的异或和:
- 定义
f[i][j] 表示从前i 个数中选出元素和为j 的方案数的奇偶性。 - 初始值
f[0][0]=1 ,其余为0 。 - 状态转移方程为
f[i+1][j]=f[i][j]\oplus f[i][j-a[i]] 。 - 答案为
f[n][j]=1 的j 的异或和。 - 第一个维度可以优化掉。
- 定义
借位拆位
- 子数组 +w^ 子数组元素和的异或和:
- 推荐先完成 ARC092D - Two Sequences
- 计算出前缀和数组
s 。 - 考虑所有的【两个前缀和相减】的结果,二进制从低到高第
k 位有多少个1 。 - 例如
k=2 时,相当于减法的结果的低3 位在[100,111] 中。但如果只考虑前缀和的低3 位,1000-1=111 本来应该满足条件,但是只取低3 位就变成0-1 了。 - 如果前缀和
\ge 2^3 ,我们可以在取低3 位后补一个2^3 ,这样1000-1=111 就是满足要求的。 - 但是,还有可能出现
1111-1=1110 这样的情况,所以减法的结果应当在[100,111]\cup [1100,1111] 中。 - 这可以用树状数组/名次树维护统计。