【MX-J2-T1】Turtle and Sequences
每次操作删一个元素,上界 n-1;序列不全相同时总能通过改成全新值续命,答案为 n-1 否则 0。
OJ: luogu
题目 ID: P10840
难度:普及-
标签:模拟思维
日期: 2026-08-14 15:01
形式化题目
给定长度
思路
先看一个可以直接验证想法的朴素解:
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-08-14 15:01
* update_at: 2026-08-14 15:20
*/
// brute.cpp:小数据暴力解,直接模拟操作过程:
// 反复寻找相邻不同的位置,删除右元素并把左元素改成"全新值"(当前最大值+1),
// 直到无法操作,统计操作次数。用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
int n;
vector<long long> a; // 当前序列
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
a.resize(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int ans = 0;
while (true) {
// 找第一处相邻不同的位置
int pos = -1;
for (int i = 0; i + 1 < (int)a.size(); i++) {
if (a[i] != a[i + 1]) {
pos = i;
break;
}
}
if (pos == -1) break; // 没有相邻不同,无法操作
// 找当前最大值,构造一个与所有元素都不同的新值
long long mx = 0;
for (long long x : a) mx = max(mx, x);
// 删除 a[pos+1],把 a[pos] 改成全新值
a[pos] = mx + 1;
a.erase(a.begin() + pos + 1);
ans++;
}
cout << ans << '\n';
return 0;
}brute.cpp 直接模拟操作过程:每轮找第一处相邻不同,删除右元素,把左元素改成"当前最大值 + 1"(一个全新值),计数直到无法操作。它与题意一一对应,但每轮要
两条关键观察直接给出答案:
- 每次操作删一个元素,序列长度从
减到 1,任何策略最多 次; - 只要序列不全相同,就总能继续操作:不全相同 ⟺ 存在相邻不同;而且把
改成"全新值"(比如当前最大值 )后,它与左右邻居都不同,操作后序列仍不全相同(长度 时),可以一直删下去。
所以答案只由"序列是否全相同"决定:
- 全相同:一次都动不了,答案是
; - 否则:可以一直删到只剩一个元素,答案是
。
下面这张表展示样例 3(1 1 45 14)用"改全新值"策略的完整操作过程:
| 操作 | 操作前序列 | 选中的相邻不同 | 操作后序列 | 次数 |
|---|---|---|---|---|
| 1 | 1 1 45 14 | (1, 45) 位置 2 | 1 46 14 | 1 |
| 2 | 1 46 14 | (1, 46) 位置 1 | 47 14 | 2 |
| 3 | 47 14 | (47, 14) 位置 1 | 48 | 3 |
观察要点:每一步把左元素改成全新值(45→46 处原值 45 被删,左元素 1 变 46;46→47 同理),新值与邻居必然不同,因此每轮都能找到下一个相邻不同位置,直到序列只剩一个元素,恰好达到上界
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-08-14 15:01
* update_at: 2026-08-14 15:20
*/
// P10840 【MX-J2-T1】Turtle and Sequences
// 每次操作删除一个元素,上界 n-1 次。
// 若序列不是全相同,总能通过把 a_i 改成全新值继续操作,答案为 n-1;
// 若全相同则无法开始,答案为 0。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int n;
long long a[MAXN]; // 输入序列
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
// 判断是否所有元素相等
bool all_same = true;
for (int i = 2; i <= n; i++) {
if (a[i] != a[1]) {
all_same = false;
break;
}
}
cout << (all_same ? 0 : n - 1) << '\n';
return 0;
}复杂度
- 时间:一遍扫描判断是否全相同,
。 - 空间:
存序列。
总结
这道题的思维含量在于把"能操作几次"还原为两个简单事实:长度每步减 1 给出硬上界
图示解析
这张 ASCII 图展示整道题的解题路线:
text
题意:相邻不同 → 删右元素,左元素改成任意整数
|
| 每操作一次,长度减 1
v
上界:最多 n-1 次(删到只剩 1 个元素)
|
| 关键:不全相同 ⟺ 存在相邻不同
v
续命手段:把 a[i] 改成全新值(最大值+1)
与左右邻居都不同 → 操作后仍不全相同 → 可继续删
|
v
答案:
全相同 → 0
不全相同 → n-1(总能删到只剩 1 个)
|
v
实现:一遍扫描判断全相同,O(n)图中主线是"上界(长度)→ 可达性(新值续命)→ 二分支答案"。真正要抓住的是:操作的自由度(任意改值)使问题从"策略选择"退化为"初始状态判定"。