思路讲解
AC代码
1 |
把这个问题看成选K个数字,然后把这K个数字全部移到第一个位置,然后把多减的代价加回来。
1 | // Problem: For the Treasury! |
赛时提交有问题是因为并没有考虑这个动态的过程,或许这种题目还是要首先搞清楚这个模拟,把这个模拟的本质,模拟的策略给搞清楚。模拟的策略就是说,至少目前为止,我走到这个点,一定是可以到达
直接模拟这个玩家,其实通过题意理解,只要这个玩家所走到的点最终能够走到视野的尽头,那么这个玩家就认为他能够走到走到终点。
那么前面有一个反向bfs,得到所有我们能到达终点的点。(赛时解法中已经想到了)。
那么这个far数组,或者说dp数组,可以通过比较朴素的前缀dp得到。
1 | vector<vector<ll> > dp(N+5,vll(M+5)); |
然后模拟这个玩家。
1 | while(!q.empty()){ |
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=78459227
1 | // Problem: Blind Alley |
那么我个人认为难点在于这个题目需要输出推动序列,其实还是有点难的,难度在于这个模拟,以及代码实现上。
1 |
首先,将( 转为1,)转为-1,始终有合法匹配(序列是合法的)就是前缀和始终为正。
通过该条件,我们能找出所有的不可交换位置(指的是你不能拿 )和这个$( $ 换 )。
通过如下程序,可以计算出来这个 )所能选的右括号有rem=N/2−fix 个,但是这样之间计算概率只能通过第一个样例,那怎么办那?遇事不决,就上dp(当然我也不会,和grok学的,这个dp)
1 | ll fix=0; |
1 |
我们赛时设计了一个算法
1 | vll siz(N+5,0); |
但是这个算法只能判断可达性(或者可达性都有点问题),瓶颈在于这个算法并不在乎达到该节点的时间。
那么有没有办法让这个算法在乎时间那?其实也简单,在该时间内,该树只有之前能到达的点。
1 | ll mn=min(time,dis); |
1 | // Problem: Head out to the Target |
一个东西,到底是在前面算,还是在后面算的,一定要搞清楚。如果是在后面算的,前面就不要算,否则会重复。

这个-1非常重要。
1 | ll cur = sum - N + K - 1; |
比较常见的运行时错误有,就是这个去取这个 vector 的最后一个数(.back()),但是 vector 为空。
1 | if (it==res.end() || it==prev(res.end())) { |
一定是超界访问了。
1 | FOR(i,1,10000){ |
1 | struct OP{ |
忘记cin了,导致了一系列问题。
1 | FOR(i, 1, N) { |
1 | struct MyString{ |

getline会把换行符给读掉。
1 | inline void __(){ |
但是普通的cin不会读掉换行符号,需要再cin.get()一下。
1 | signed main() |
https://ac.nowcoder.com/acm/contest/108300/D
那么WA的原因在于这个有一些小问题,就是加粗部分赛时那发WA的没有加,即初始化阶段也要加上答案判断。
1 | FOR(i,1,N){ |
树上倍增,只能解决最高点,不能解决最低点,或者至少需要转化。
这个倍增还是太阴间了。就是一般来说,找到的点就是答案的情况,还是要特判一下。
1 | ll low=tr.findlow(u); |
https://acm.hdu.edu.cn/contest/view-code?cid=1174&rid=20171
注意这里不能简单+1(下方的代码是对的)(简单的+1就是查lr[i].SE的idx,然后加的地方直接就是idx+1,这个是不行的,我们不能默认这两个区间是相交的)
1 | mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count()); |
向上取整除法可以这样写,没有精度问题,非常对呀。注意C特性,x/2实际上是往0取整的,所以x<0的时候就不用我们操心了,C自动向上取整。
1 | inline ll chu(ll x){ |
状压要特别小心差一错误。(就是加粗,下划线的地方必须要+1)
1 | FOR(s,0,(1<<N)){ |
这边一定要写0ll,否则很有可能会爆炸
1 | ll sum=accumulate(all(A),0ll); |
自定义结构体使用unique,需要定义==和<,两者缺一不可。
1 | struct Point{ |

否则会被形如这样的数据卡掉。
1 | class Solution { |
遇到这两个东西,看看是不是这个递归退出条件的问题?
这个循环退出条件特别容易忘记。
1 | function<void(ll,ll,ll,ll)> dfs=[&](ll a,ll b,ll c,ll d){ |
C++是取余操作,会得到负数,进而导致错误。
1 | FOR(i,1,N-1){ |
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=78695197
1 | ll ans=2; |
模拟宜采用正向逻辑。
0-based的话星期六星期日就是星期5,6。
1 | if(idx==5 || idx==6){ |
节点表示范围是 [le,rr],然后根节点表示范围是[0,sz−1]
1 | int dis(int o){return dep-__lg(o);} |
1 | // 找到最靠近r的符合位置 |
千万不要这么干,因为不仅更新的时候要调用,下传标记也要调用,你能保证两个线段树的懒标记状态一样吗?这个是不可能的,因为你也不可能同时更新,询问两个线段树,除非把他们合为一个。

一定要it,不能it。

不要去想超范围转移哪些是正确的,而是直接给所有超范围部分赋值-INF。
正难则反,去想哪些超范围转移是正确的。(一般是起始位置的转移位置)
1 | vector<vll> A(N+5,vll(M+5)); |
检查器最好检查一下两个线段的交点是不是一个线段的端点?这种情况需不需要特殊处理?
1 | auto check=[&](Line a)->bool { |
一定要是>号。
1 | while (!pq.empty()) { |
思路就是用异或操作可以对齐位数,然后使用最高位,不断左移异或。
总的来说我就是看题解的。


https://ac.nowcoder.com/acm/contest/view-submission?submissionId=78402363
1 | // https://ac.nowcoder.com/acm/contest/108300/B |
这边多进行了一次操作导致WA了。
1 | }else{ |