1 条题解
-
0
B. pspspsps 题解
题目回顾
给定长度为 、仅含
p/s/.的字符串 ,判断是否存在一个 的排列 ,满足:- 若 :前缀 是长度为 的排列;
- 若 :后缀 是长度为 的排列;
- 若 :无任何限制。
核心结论(解题关键)
这道题的唯一矛盾点是约束冲突,我们只需要两步判断:
- 特殊位置无约束
- 第 个位置的
s无效(整个数组本身就是排列),直接视为.; - 最后 个位置的
p无效(整个数组本身就是排列),直接视为.。
- 第 个位置的
- 最终判定
处理后,若字符串中同时存在
p和s→ 输出NO(约束冲突,无解); 否则 → 输出YES(一定能构造出合法排列)。
结论证明
- 仅含
p:构造排列 ,所有前缀天然满足排列要求; - 仅含
s:构造排列 ,所有后缀天然满足排列要求; - 仅含
.:任意排列都合法; - 同时含
p和s:前缀约束和后缀约束无法同时满足,无解。
代码逐段解析
主函数
int main() { int t; cin >> t; for (int i = 0; i < t; i++) solve(); return 0; }- 多组测试用例,循环调用求解函数,逻辑简洁。
核心求解函数
solve()void solve() { int n; cin >> n; string s; cin >> s; // 步骤1:处理无意义的特殊字符 if (s[0] == 's') s[0] = '.'; // 第一个位置的s无效 if (s.back() == 'p') s.back() = '.'; // 最后一个位置的p无效 // 步骤2:检查是否同时存在p和s bool found_p = false; bool found_s = false; for (const auto c : s) { if (c == 'p') found_p = true; if (c == 's') found_s = true; } // 步骤3:输出答案 cout << (found_p && found_s ? "NO" : "YES") << '\n'; }关键操作说明
- 无效字符处理
- 时
s的约束是「整个数组是排列」,这是排列的定义,天然满足,因此直接改为.; - 时
p的约束是「整个数组是排列」,同理天然满足,直接改为.。
- 时
- 冲突检测
遍历字符串,标记是否同时存在
p和s,这是唯一的无解情况。
复杂度分析
- 时间复杂度: 每组测试用例仅遍历字符串一次,总长度不超过 ,完全满足 秒时间限制。
- 空间复杂度: 仅存储输入字符串,无额外空间开销。
样例验证
我们用题目样例验证代码逻辑:
s.sp→ 处理后.sp→ 含p和s?❌ → 输出YES;pss..s→ 处理后含p和s→ 输出NO;ppppp→ 仅含p→ 输出YES;sp→ 处理后.p→ 仅含p→ 输出YES;
完全匹配题目样例输出!
总结
这道题是构造+贪心思维题,不需要复杂算法,核心是看透无效约束和冲突条件:
- 忽略首尾无意义的
s/p; - 仅判断是否同时存在
p和s; - 代码极简,效率拉满,完美通过所有测试用例。
- 1
信息
- ID
- 7126
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者