百炼成钢八总结
百炼成钢八总结
废话不多说,直接看题。
另外,现在是每道题写完当场写总结,所以每道题都有。
NKOJ 5591 果老师的位运算
假做法
思路:玄学
实现方法
-
全部或起来。
-
为啥呢?
-
因为在数据特别大的时候,几乎每一位都有一个数是 \(1\),那么全部或起来和删去哪个数区别几乎是没有的。
-
但是样例都过不了
正解
思路:前缀和
实现方法
- 一个数组是前缀和,另一个是后缀和,通过这两个值就能求出当前的或值。
NKOJ 5610 异或序列
思路:双指针
实现方法
- 很明显这道题是让我们看有没有进位。
- 进位就是与运算。
- 很遗憾与运算不符合前缀和的性质,所以与运算不能直接前缀和。
- 好消息是加法和异或都满足,所以可以通过这俩来求与。
- 接下来用双指针锁定区间就好了。
注意事项
- 不开祖宗见
long long
。
NKOJ 2221 【位运算】"1"的数量
思路:贪心
实现方法
-
把整个数字的二进制倒过来。
-
然后对于每一个 \(1\) 都去看它后面是谁。
- 如果是 \(0\) 就和 \(1\) 交换。
- 如果是 \(1\) 就把它换到最前面去。
-
倒序输出答案。
NKOJ 6404 [CSP-S 2019 Day1]格雷码
思路:位运算
实现方法
- 格雷码的性质是第 \(k\) 个格雷码是 \(k\operatorname{xor}\frac{k}2\) 反过来。
注意事项
- 开
unsigned long long
因为long long
只装得下 \(2^{63}\) 。
NKOJ 7363 位运算
思路:位运算
实现方法
- 注意到异或是不进位的加法,与是进位部分的一半。
- 所以有
\[x-2y=x \operatorname{xor} y
\]
- 但是在 \(x-2y<0\) 或 \((x-2y) \operatorname{and} y=1\) 时不成立。
- 因为第一种小于零,第二种推倒一下就知道 \(x \operatorname{and} y\) 和 \(x \operatorname{xor} y\) 的数位不可能有一个数位同时为 \(1\)。
NKOJ 47444 异或方程
思路:位运算+组合数学
实现方法
- 这道题中有 \(x\operatorname{xor}y\) 的结果。
- 我们发现如果 \(x \operatorname{xor} y\) 中一定是 \(x\) 和 \(y\) 相同的是 \(0\),不同的即 \(x\) 是 \(0\) 或 \(y\) 是 \(0\) 是 \(1\)。
- 所以实际上就是将异或结果中的 \(1\) 分配给两个数。
- 用组合数计算即可。
- 注意特判 \(a-b\) 是奇数以及 \(a \operatorname{and} b\) 和 \(a \operatorname{xor} b\) 同时为 \(1\) 的情况。
NKOJ 3679 找数2
思路:位运算
实现方法
- 由于给出了异或值,只需要把它分解为两个完整的数。
- 通过
lowbit
得到异或的第一个 \(1\)。 - 看输入的每一个数能不能和它与成 \(0\) 。
- 如果能,就分到第一个数。
- 不能就分到第二个数。
- 最后出现偶数次的还是会被抵消掉。
注意事项
- 不要用
bits
或者iostream
!会MLE
。
NKOJ 3671 最大异或
思路:位运算
实现方法
- 在 \(l\) 和 \(r\) 范围内,能异或的最大值应该是 \(2^x-1\) 唯一问题是不知道 \(x\) 是多少。
- 由于 \(x\) 要越大越好,所以直接去找 \(l\) 和 \(r\) 之间的极限,可以直接将 \(l\) 和 \(r\) 异或,然后看有多少位。
注意事项
- 记住
1<<x
在int
范围内,要么用pow()
要么变成1<<xLL
NKOJ 3680 找数3
思路:位运算
实现方法
- 这道题实际上和 NKOJ3679 差不多。
- 我们需要提前把 \(1\sim n\) 的异或值求出来。
- 然后和输入值异或。
- 分类的时候需要加入 \(1\sim n\) 的值。
NKOJ 3096 【伪语法基础】输入输出练习3
思路:位运算
实现方法
- 这道题和 NKOJ3679差不多。
- 只是题目中没有把所有数的异或值告诉我们。
- 但是直接去求一遍是不现实的,因为数组都不能开。
- 我们可以直接分类,但是把每种情况都算出来,相当于分64类。
- 再去找有没有合法的。
注意事项
- 不要用
bits
或者iostream
!会MLE
。
NKOJ 3098 【伪语法基础】输入输出练习1
思路:位运算
实现方法
- 略
NKOJ 3099 【伪语法基础】输入输出练习2
思路:位运算
实现方法
-
考虑每个二进制位,扫一遍所有数之后
-
如果某个二进制位上,1出现了3k+0次,则那个数的二进制的这一位是0;
-
如果某个二进制位上,1出现了3k+1次,则那个数出现了1次,且那个数的二进制的这一位是1;
-
如果某个二进制位上,1出现了3k+2次,则那个数出现了2次,且那个数的二进制上这一位是1。
-
如果既有位上1出现3k+1次,又有位上1出现3k+2次,说明程序写错了;
-
-
n可能是3k+1或3k+2,可以帮助判断那个数的次数。
-
开两个变量a1,a2,分别记录哪些位上1出现了3k+1和3k+2次,
-
每次读进来一个x后做相应的更新操作。
-
a1' = (a1 ^ (a1 & x)) | (x ^ (x & (a1 | a2)))
-
a2' = (a2 ^ (a2 & x)) | (a1 & x)
注意事项
- 不要用
bits
或者iostream
!会MLE
。 - 注意每次赋值的时候会盖住原来的值,所以应该把新值计算完了再赋值。
NKOJ 2223 【位运算】飞行员兄弟的冰箱
思路:DFS
实现方法
- 这道题 DFS 的方法很多,我开始用的错误的一种,导致一直
RE
。 - 一种简单的方法是将现在移动的把手的坐标作为 DFS 的值。
- 因为将同一个位置移动两次,就会变回去,所以不会出现重复的情况,只需要考虑移动顺序。
- 然后就是按部就班地写。
- 如果到边界了,就判断能不能打开冰箱,如果能,就更新答案。
- 如果没到边界,就考虑当前这个点操不操作,然后递归下去。
NKOJ 3672 "加"与"异或"
思路
- 手玩一下样例就会发现一个奇特的规律,答案就是 \(\frac{A+B}2\) 和 \(\frac{A-B}2\) 。
- 这是为什么呢?
- 因为异或是不进位的加法,与是加法的进位部分的一半。
\[A+B =& \text{不进位的部分}\times2+\text{进位的部分}
\\
A-B =& \text{进位的部分}
\]
- 所以答案就是这样。
- 那为什么 \(A+B\) 一定是偶数呢?
- 因为如果 \(A+B\) 不是偶数,必然一奇一偶。
- 但是如果 \(A\) 为奇数,那么进位的部分也就是 \(B\) 也是奇数,所以不可能。
实现方法
- 略。
NKOJ 3673 "异或"与"或"
思路:位运算
实现方法
- 这道题其实是在考察或和异或的性质。
- 因为或和异或都不能凭空产生或者消除 \(1\) 。
- 所以如果出现两个字符串有一个全 \(0\) 要变成 \(1\) 那就不行,否则就可以。
- 还有如果长度不一样就想都别想了。