1 条题解
-
0
自动搬运
来自洛谷,原作者为

yanxiashi
总是这样搬运于
2025-08-24 22:49:29,当前版本为作者最后更新于2023-08-17 16:25:24,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
比赛时有事,晚进早退,就打卡了一下 T1,估计起码有橙(怎么可能是红)。。。
这是一篇有详细过程的成长类题解。
题意(还原向)
设 表示一条直线最多能穿过 的网格图的格子数。
- 给定 ,求 ;
- 给定 ,找到 ,满足 ,且 尽可能小。求 的最小值对 取模的结果。数据保证 。
题目说得很清楚。
思路(逐步向)
问题一:
对于问题一,我们可以先寻找规律,通过在草稿纸上我们画图得到这样的结果:

m\n 1 2 3 4 5 6 1 1 2 3 4 5 6 2 2 3 4 5 6 7 3 3 4 5 6 7 8 4 4 5 6 7 8 9 5 5 6 7 8 9 10 6 6 7 8 9 10 11 猜测 。
证明:
考虑数学归纳法:
- 时,直线只能穿过一行或一列的格子,总数为 , 同理。
- 假设:对于任意的 的网格图,一条直线最多能穿过 个格子。试证明对于 和 的网格图也成立。
- 对于 的网格图,假设直线从左上角顶点到右下角顶点,穿过了 的网格图的 个格子,然后再穿过额外的一行格子,总数为 。
- 又因为 和 互换后不影响最后的答案,所以 的网格图同理。
- 综上所述,可以证明一条直线最多能穿过 的网格图的格子数是 。
命题得证。
于是问题一优雅地解决了。
问题二:
至于问题二,需要我们使用一些数学知识。
- 令 ,结果不变;
- 此时易知 ;
- 由问题一的结论我们知道 ;
- 要求 的最小值,又由于 和 为定值,所以只要求 的最小值;
- 根据均值不等式,当 时, 最大;当 和 之间相差越大时, 最小。
- 由于我们已经规定 了,让 和 之间相差最大的做法,就是让 不变,增加 的值;
- 又 ,所以 ,。最终的答案即为 。
- 注意取模。
推理结束,接下来是代码时间……
代码(丑陋向)
30pts Code:
(点击上方超链接可查看评测记录)
事实证明第二问的代码没有那么好写,下面是一篇不良代码,我们看一下哪里出了问题。
1 else { 2 cin >> Q; 3 n %= mo; m %= mo; Q %= mo; 4 if(n < m) swap(n,m); 5 n2 = (Q - m + 1) % mo; 6 cout << (n2 * m - n * m) % mo << "\n"; 7 }- 第三行和第四行的顺序颠倒了——我们不能先取余再交换,因为取余后会改变大小关系。
- 因为取余后会改变大小关系,所以第五行和第六行会出现负数,这是不允许的,所以需要在括号内加上模数,来规避错误的负数。
- 另外,第六行的括号内需要减去一个二次的多项式 ,必须要加上 才能合法计算,于是我们不得不使用乘法分配律,把答案 换成 ,这样只用在括号内加一次模数就好了。
AC Code:
(点击上方超链接可查看评测记录)
#include<bits/stdc++.h> using namespace std; const int mo = 998244353; long long T,n,m,op,Q,n2,m2; int main(){ cin >> T; while(T--){ cin >> op >> n >> m; if(op == 1) cout << (n + m - 1) << "\n"; else { cin >> Q; Q %= mo; if(n < m) swap(n,m); n %= mo; m %= mo; n2 = (Q - m + 1 + mo) % mo; cout << ((n2 - n + mo) * m % mo) % mo << "\n"; } } return 0; }创建博客:[2023.08.17 16:25]
完成题解:[2023.08.17 18:58]
上传题解:[2023.08.17 19:28]
修改题解:[2023.08.17 23:00]
简化题解:[2023.08.18 18:55]
- 1
信息
- ID
- 8888
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 2
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者