1 条题解
-
0
问题理解
我们需要构造一个长度为 的排列,使得可以执行尽可能多的“缩操作”。
缩操作的定义:
- 选择一个下标 (),满足 且 (即 是严格局部最大值)
- 移除
目标:最大化可以执行的操作次数。
关键观察
-
最大元素的位置
在整个排列中,最大值 只能出现一次。只要最大值 不在两端(即不在第一个或最后一个位置),它就一定是局部最大值(因为所有其他元素都比它小)。因此,只要 不在两端,它就可以被移除。 -
移除后的变化
当我们移除 后,剩下的排列中会出现新的最大值(即 )。同样地,只要 不在当前数组的两端,它就可以被移除。 -
过程持续
这个过程可以一直持续,直到数组中只剩下两个元素。因为:- 当数组长度为 时,没有下标 满足 (因为 )
- 所以无法再执行任何操作
-
最大操作次数
初始数组长度为 ,最终数组长度为 ,每执行一次操作数组长度减少 ,因此最多可以执行:次操作。
如何达到最大操作次数?
我们需要让每次移除的都是当前的最大值。也就是说:
- 首先移除
- 然后移除
- 然后移除
- ...
- 最后移除
剩下的两个元素是 和 。
关键条件:每次要移除的最大值必须不在两端。
构造方法
一种简单的构造是:
- 把 放在最后
- 把 放在最前
- 其余数字 按顺序放在中间
即:
验证:
- 在位置 (从 开始计数),左右都有元素 → 可以移除
- 移除 后, 成为新的最大值,仍然在中间 → 可以移除
- 依此类推,直到剩下
为什么这样可行?
在排列 中:
- 对于任意 (), 的左边是 ,右边是 (或当 时右边是 )
- 由于所有数字都不同,且 是当前剩余元素中的最大值时,它一定大于左右邻居
- 因此 满足局部最大值的条件,可以被移除
算法步骤
对于每个测试用例:
- 输出
- 最后输出
复杂度
- 时间复杂度: 每个测试用例
- 空间复杂度:(不考虑输出)
代码实现
#include <bits/stdc++.h> using namespace std; void solve() { int n; cin >> n; for (int i = 2; i <= n; i++) { cout << i << ' '; } cout << 1 << endl; } int main() { int t; cin >> t; while (t--) solve(); return 0; }
示例验证
示例 1:
- 输出:
- 操作过程:
- 移除 (位置 ):
- 无法继续
- 操作次数 = ✅
示例 2:
- 输出:
- 可以执行 次操作,达到最大值 ✅
结论
任何满足 和 在两端的排列都能达到最大操作次数 。最简单的构造是:
- 1
信息
- ID
- 7285
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 1
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者