比赛链接:https://codeforces.com/contest/1516
A
题目大意
n个元素,最多k次操作,每次操作选择两个元素,其中一个++另一个–,不能出现负数。输出最多k次操作后,字典序最小的元素序列。
解题情况
一共 wa 了两发。
wa了第一发的时候没有检查语法错误。
而是直接找逻辑错误,结果改了跟没改一样wa了第二发。
wa了第二发的时候才认真找错误:
发现错误有两点:
- 定义加了 long long 但输入的时候用的是%d 而不是%lld
- 题目说的是字典序最大,并且没上限,那只需要每次选择最前面的首非0项,和最后一位就可以。 而我的做法是把最前面那项减到0后,l++,r–。不能r–。
B
题目大意
n个元素,可进行任意次操作,把两个相邻元素的合并成他们的异或和。
思路
最开始以为跟区间dp有关,但n是2000级别,区间dp是O(
n
3
n ^{3}
n3).
后面一想,反正是相邻的,把它分成两个区间,然后每个区间都异或和,枚举 k (两个区间的边界)。异或和 就用 一个前缀异或和、一个后缀。
因为异或具有交换律,结合律。
结果wa了一发,被3 3 3.这个数据hack了。
因为还有分成3段的情况。
于是在判断完两个区间后,如果还是NO就判断三个区间的情况。
枚举中间区间的长度,利用前缀异或和的性质:
像前缀和一样,sum[l,r] = sum[r] - sum[l], 换成sum[l,r] = sum[r] ^ sum[l]. 来处理O(1)处理中间区间,这样复杂度是O(
n
2
n^{2}
n2).
解题情况
也wa了两发,
第一发 把后缀和写错了,把ed[i] = ed[i+1] ^ a[i],写成了ed[i] = ed[i-1] ^ a[i]。
第二发 就是只考虑了两个区间。
需要注意的点
队友被hack了,是因为异或和优先级小于 ==。要写成这样 if ( (sum[i]^sum[j])==sum[i] )
C
题目大意
n个元素,求删去最少的元素,使得 它不能分成两个 总和相等的集合。
思路
两个集合相等,自然而然想到了天平问题。
看一下n=100,a < 2000,没错可以用01背包来判断,当前集合是否存在 可以分成两个总和相等集合的情况。
但后面一想,如果每次删除都判断,时间肯定会炸,而且也不知道要删多少次。
于是后面在01背包的dp中,记录非0的 放入物品最多的情况。但最后也没调出来。
看别人代码发现思路很简单,先01背包判断。
如果能分,就删除一个奇数。
如果没有奇数,就把所有的数都除2,直到有一个奇数。
也就是说,最多只删除一个元素就可以。
为什么可以除2能,因为所有元素都是偶数的情况下,全部都除2不影响它们之间的相对倍数关系,也就是说,原来能凑成的,之后也能凑成。
解题情况
赛时没写出来。
总结
- 交之前注意基本语法问题(%lld)
- 位运算的优先级 小于 等号,使用位运算就要用括号!!
- 先思考再码代码,三题都是题目还没思考情况,自己的算法没有进行合理性验证就上手,导致思路固定,后面很难改思路。
- 赛时的思维能力还需要提高,但比以前其实提高了不少,起码每题一看就能想到正确的解法(B题立马前后缀处理,C题很快就意识到是01背包),只是算法的细节没有考虑清楚。
- 继续冲!!!