牛客小白月赛39C - 奋发(数学规律 + 贪心 + 模拟 + *1600)
牛客小白月赛39C - 奋发(源地址自⇔牛客)
tag
⇔数学规律、⇔贪心、⇔模拟、⇔*1600左右
题意
给定两个长度为 \(N\) 的非降序列 \(a,b\) 以及两个初始为 \(0\) 的变量 \(A,B\) 。现在按如下规定进行操作:
- 若 \(A=a_n\) 并且 \(B=b_n\) ,直接结束所有操作;
- 如果存在 \(a_k=A\) 并且 \(b_k>B\) , \(++B\) ;
- 如果存在 \(b_k=B\) 并且 \(a_k>A\) , \(++A\) ;
- 如果上述的条件均不满足,则任选一个 \(+1\) 。
在每一次操作之后,如果存在 \(A=B\) ,则令 \(ans + 1\) 。直到操作结束,输出 \(ans\) 的最大值。
一组样例,满足 \(1≤N≤3∗10 ^6 ;1 \leq a_i,b_i\le 2*10^9\) 。
思路
赛时小结
我试图从形象的角度思考寻找规律,所以我出了很多个测试集并且尝试总结,然而直到比赛结束都没能解出。赛后复盘时我发现自己刚开始的思路就已经非常接近正确答案了,但是问题在于没有对于一种情况进行特判。下方的思路我将从抽象+形象结合的角度进行解剖,也算是提升一下自己的抽象思考能力吧。
正解
很显然,初始的情况 \(A=B=0\) ,直到其满足操作 \(2\) 和 \(3\) 之前,都需要执行操作 \(4\) 。这一阶段,我们依次让 \(A+1,B+1\) 这样循环,会使得 \(ans=ans + min\{a_i,b_i\}-0\) 。在这之后会重复步骤 \(2\) 和 \(3\) ,而这两步操作不会对 \(ans\) 造成影响。
例如:"0,0" -> "2, 3"。
过程为:"0,0" -> "2,2" -> "2,3"。从过程 \(_1.\) 到 \(_2.\) 执行的是操作 \(4\) (答案 \(+2\) ),从过程 \(_2.\) 到 \(_3.\) 执行的是操作 \(2\) (答案不变化)。
再考虑接下来的操作,我们需要再次执行操作 \(4\) ,使得 \(A=B=max\{a_i,b_i\}\) ,这一步操作过程中不会对 \(ans\) 造成影响,而当达成 \(A=B\) 时,会使得 \(ans = ans + 1\) ,但是注意,如果在上一步操作中 \(a_{i-1}=b_{i-1}\) ,那么这一步将被略去!
例如:"2,3" -> "5,6"。
过程为:"2,3" -> "3,3" 。执行操作 \(4\) (答案 \(+1\) ),然后重复。
例如:"3,3" -> "5,6"。
过程为:直接重复。
重复,直到完成操作。
AC代码
点击查看代码
void Solve() {
int ans = 0, xx = 0, yy = 0;
int n; cin >> n;
for (int i = 1; i <= n; ++ i) {
int x, y; cin >> x >> y;
int w = min(x, y) - max(xx, yy) + (xx != yy);
ans += max(w, 0);
xx = x, yy = y;
}
cout << ans << endl;
}
错误次数
(赛时1次)忘记特判 \(a_{i-1}=b_{i-1}\) 的情况。
(赛时无数次)尝试穷举所有情况失败。
文 / WIDA
2022.03.20 成文
首发于WIDA个人博客,仅供学习讨论