如何有逻辑的实现思路
我最近发现,很多时候我知道了思路,想清楚了做法,却没有动手实现。
很大一部分原因是我并不知道该怎么下手,从哪里开始写,怎么写,写什么。
昨天觉得这样不好,时间长了之后代码能力就完全退化了,所以想了想,应该怎么做。
以这道题为例:
Solution
这道题就是说从高位开始考虑,看一下这一位都是 \(1\) 的够不够 \(m\) 个,然后够了的话就把不是 \(1\) 的扔掉免得之后不好判定。
如果这一位不够了那只能是 \(0\) 了,然后如果刚好不够 \(m\) 个了就说明这一位也只能是 \(0\),最后就能确定答案。
然后具体怎么维护这些数呢,显然我们暴力取出来复杂度就寄了。但是你考虑这个贪心过程,我们每次相当于是对每一个位置保留至少 \(m\) 个。
可以注意到我们保留最大的,显然不会比使用更小的获取的答案更劣,所以我们不妨,对每一位都只保留 \(m\) 个,数量级在 \(O(m \log V)\) 左右。
这个复杂度就是可以接受的了(实际卡不满),于是我们现在做的事情就是把这些数取出来,这很简单,用我们 Count on the tree 的套路,每个节点维护从根到它的值域线段树,然后利用可持久化维护,做一个树上差分,同步维护四个指针就行了。
现在我们知道了思路,应该怎么实现呢?
首先明确一下,思路的每个细节大致能知道怎么实现,然后如果有细节问题先想清楚,不然的话会浪费大把时间。
比如说贪心部分,大概知道是从高位开始考虑,逐位确定答案。
所以实现上应该是先枚举位数,然后看一看取出来的这些数当中,那些能让当前位为 \(1\),把这些数标记(注意,我们实现的时候不一定是标记,如果按照自己写出来的思路直接实现很多时候容易过于麻烦),check 一下个数够不够 \(m\),更新答案,删掉数就行了。
然后步骤就是,根据题面给出的输入格式,在 main()
当中一行一行写下去。
比如这题是先给出一棵树。
于是我们知道应该存图,如果使用前向星的话需要 memset
。
然后看一眼数据范围,\(10^6\),要开双向边,于是我们写下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
然后注意到还要有权值,继续写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
接下来读到有 \(Q\) 组询问,需要强制在线解密。
于是写下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
之后考虑询问的部分,我们应当依次做什么。
首先我们要做的就是,提取出路径上的一些数,然后贪心。
提取的话需要使用可持久化线段树。要维护每个节点到根的链。
然后通过树上差分得到对应的线段树,在它上面线段树二分,之后把数提取出来。
那么我们首先需要写一个离散化,为了节省线段树的空间(这题空间卡的比较死)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
然后我们需要建出这个线段树,首先需要 dfs,而且树上差分要求 LCA,于是写一个倍增 LCA:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
|
然后就写个可持久化线段树就行了,记得在 dfs 里面加一行来建树。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
|
剩下的事情就是写一个贪心了,先提取出要用的数。
然后按位考虑,每一位选一些数出来看看够不够,如果够就删掉不满足条件的。
最后输出答案就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
|
剩下的就是调试了(这个代码不保证能过)