一维围棋 (Div. 2 Only)
来源:
- ACM-ICPC Japan Alumni Group Summer Camp 2019. Problem A, AiGo
- Petrozavodsk Summer 2020. Day 5: JAG Summer+ Opening Contest. Problem A, AiGo
QOJ 链接:https://qoj.ac/problem/1335
tutorial by Wu_Ren
枚举哪个位置去放棋子,首先如果上面已经有棋子就不能放,然后向左向右如果都是连续一段白再接一段黑,那么也不能放,否则一定能放。放了之后向左向右分别扫一遍即可知道占领了多少黑棋。
复杂度 O(n) 或 O(n2)。
斜二等轴测图 (Div. 1 + Div. 2)
来源:
- 2018 Multi-University Training Contest 3. Problem B, Visual Cube
- Petrozavodsk Summer 2020. Day 3: Songyang Chen Contest 3. Problem B, Visual Cube
QOJ 链接:https://qoj.ac/problem/1266
tutorial by Wu_Ren
按照题意模拟即可,复杂度 O(T(a+b)(b+c))。
盒子里的糖果 (Div. 2 Only)
来源:
- Petrozavodsk Summer 2021. Day 4: Shanghai ICPC Camp 2021 Onsite Day 1 by PKU. Problem F, Interval Shuffle
QOJ 链接:https://qoj.ac/problem/1848
tutorial by hehezhou
算法一
令 dpi,j 表示 i 次操作后,aj 的最大值。
那么有: {dpi,j=dpi−1,jj∈[1,li)⋃(ri,n]dpi,j=max
即只需考虑 i-1 步时的最大值即可推出 i 步后的最大值。构造某位的最大值只需按照 dp 转移式逆推即可。
时间复杂度 O(n^2)。
算法二
考虑用线段树优化上述过程:
- 计算 \max_{k\in [l_i,r_i]}dp_{k} 即为一次查询区间最大值。
- 更新 dp 值可以表示为一次区间加和一次区间取 \max。
这是一个经典线段树问题,可以在 O(n\log n) 的时间复杂度内解决。
冲塔 (Div. 1 + Div. 2)
来源:
- National Olympiad in Informatics 2022. Problem 3, Towers
QOJ 链接:https://qoj.ac/problem/3873
tutorial by p_b_p_b
先不管“每列只能冲至多两个塔”的限制,直接先把每行最左和最右的塔都冲掉。
这时候当然可能会出现某一列超过两个塔了。但是往好处想:如果超过两个塔,是不是说明中间那个塔就不需要冲了呢?
因此可以每次找到最靠右的一列,使得这一列有超过两个塔,然后把中间的那些塔全都往左移动一位。
不难发现每次这样操作之后仍然满足每个塔都被覆盖,并且 O(n) 次操作之后就不会存在冲了超过两个塔的列了。
用 set 维护,复杂度 O(n\log n) 。
波特分组 (Div. 1 Only)
来源:
- Petrozavodsk Winter 2020. Day 7: Gennady Korotkevich Contest 5. Problem F, Flip
- XX Open Cup named after E.V. Pankratiev, Grand Prix of Gomel. Problem F, Flip
QOJ 链接:https://qoj.ac/problem/1427
tutorial by feecle6418
设 S=\sum k。
算法一
直接枚举每枚硬币哪面朝上,时间复杂度 O(q2^{2n}),可以通过第一个子任务,期望得分 9。
算法二
考虑先枚举每一种情况,用子集和变换预处理每种输入哪些会有贡献,时间复杂度 O(2^{2n}n+S),可以通过前两个子任务,期望得分 25。
此外,可能存在一些高复杂度算法,可以通过前三个子任务。
算法三
首先,给定一种分组状态,它出现的概率是多少?设最后一个分到 A 组的人编号为 i_A,最后一个分到 B 组的人编号为 i_B,则概率为 2^{-\min(i_A,i_B)}。
对于每组询问,不妨假设全分在 A 组,枚举 \min(i_A,i_B)=p 的值,计算分组方案数:
- p=b_k,此时分组方案数为 \binom{b_k-k}{n-k}。
- p 位置分在 B 组,不妨设 b_i < p < b_{i+1},则分组方案数为 \binom{p-i-1}{n-1}。对于固定的 i,p-i-1 构成区间,恰当预处理前缀和可以 O(1) 求出。
- p>b_k 且 p 位置在 A 组,则分组方案数为 \binom{p-k-1}{n-k-1}。对于每种出现的 k,分别 O(n) 预处理该式与概率的乘积的后缀和即可。
因为不同的 k 只有 \sqrt S 个,所以时间复杂度 O(n\sqrt S+S),期望得分 100。注意边界。
本题也存在线性做法。
别急 (Div. 1 Only)
来源:
- XXII Open All-Siberian Programming Contest named after I.V. Pottosin Final tour, II day. Problem 11: Captivating process
- XXII Open Cup named after E.V. Pankratiev, Grand Prix of Siberia. Problem 11: Captivating process
QOJ 链接:https://qoj.ac/problem/4758
tutorial by Y25t
建两张有向图 F,G,对所有 1\le i\le n 在 F 中连有向边 (i,f_i),在 G 中连边 (i,g_i)。那么它们分别形成基环内向森林。
对于一个点 u ,若它能沿着 F(或 G)中唯一出边走若干步能回到 u,则称它为 F(或 G)中的环点,否则称它为 F(或 G)中的树点。定义 dep^F_u 为在 F 中 u 第一次走到环点所需步数。若 u 在 F 中是环点,则 dep^F_u=0,同时定义 l^F_u 为 u 所在环的长度,d^F_u 为 u 在其所在环上的编号(满足 0\le d^F_u< l^F_u 且 d^F_{f_u}\equiv d^F_{u}+1\pmod{l^F_u})。类似地定义 dep^G,l^G,d^G。
对于一块石板 (x,y),不妨设 dep^F_x\le dep^G_y。考虑将时间分为 [0,dep^F_x),[dep^F_x,dep^G_y),[dep^G_y,+\infty) 三段,分别判断是否会裂开。
[0,dep^F_x)
在这段时间里,x 为在 F 中的树点,y 为在 G 中的树点。
该石板会在这段时间中裂开,当且仅当存在点 u 使得以下三个条件同时满足:
- dep^F_x-dep^F_u=dep^G_y-dep^G_u,即 dep^F_u-dep^G_u=dep^F_x-dep^G_y。
- 在 F 中 u 是树点,且为 x 的祖先。
- 在 G 中 u 是树点,且为 y 的祖先。
于是将询问离线后在 G 的树部分进行 dfs。用 std::set
或动态开点线段树维护 2n 个线段集合 S_i(-n\le i\le n)。在进入一个点 u 时,在 S_{dep^F_u-dep^G_u} 中插入线段 [dfn^F_u,dfn^F_u+sz^F_u-1](其中 dfn^F,sz^F 为在 F 中的 dfs 序和子树大小),回溯时撤销。对于询问 (x,y),在进入 y 后判断 S_{dep^F_x-dep^G_y} 中是否有线段覆盖了 dfn^F_x 即可。
该算法加一些简单特判后可通过子任务 7。
[dep^F_x,dep^G_y)
在这段时间里,x 为在 F 中的环点,y 为在 G 中的树点。
该石板会在这段时间中裂开,当且仅当存在点 u 使得以下三个条件同时满足:
- d^F_u-d^F_x\equiv dep^G_y-dep^G_u\pmod{l^F_u} 即 d^F_u+dep^G_u\equiv d^F_x+dep^G_y\pmod{l^F_u}。
- 在 F 中 u 是环点,且与 x 在同一环中。
- 在 G 中 u 是树点,且为 y 的祖先。
于是可以用类似的 dfs 进行求解。
该算法加一些简单特判后可通过子任务 6。
[dep^G_y,+\infty)
在这段时间里,x 为在 F 中的环点,y 为在 G 中的环点。
该石板会在这段时间中裂开,当且仅当存在点 u 使得以下三个条件同时满足:
- d^F_u-d^F_x\equiv d^G_u-d^G_y\pmod{\gcd(l^F_u,l^G_u)}
- 在 F 中 u 是环点,且与 x 在同一环中。
- 在 G 中 u 是环点,且与 y 在同一环中。
用 std::set
维护三元组即可简单判断。
该算法可直接通过子任务 5。
结合以上三个算法即可通过本题。