1 条题解
-
0
📝 题目大意
给定一个长度为 的字符串 ,表示 个保龄球瓶的状态(
1为竖立,0为倒下)。球瓶按三角排列,共分为 列。判断当前排列是否为"分裂"(Split):球瓶 必须倒下,且存在两列都有竖立的球瓶,但它们之间有一列所有球瓶都倒下了。💡 解题思路
-
题目分析:
- 输入仅为长度 的
01串,没有复杂的数据范围约束。 - 关键是将 个球瓶映射到 列中,然后检测"两端有竖立、中间有空列"的模式。
- 球瓶 竖立时直接排除(输出
No),这是必要条件。
- 输入仅为长度 的
-
算法推导:
-
列映射:根据题目图示, 个球瓶分别属于 列。标准代码中用数组
map[10] = {4,3,5,2,4,6,1,3,5,7}表示球瓶 (-indexed)所属的列编号()。例如球瓶 和 都属于第 列,球瓶 和 都属于第 列。 -
列状态压缩:遍历 ,若某球瓶竖立(
s[i] == '1'),则将对应列标记为 (col[map[i]-1] = 1)。这样 数组的每个元素表示该列是否有竖立的球瓶。 -
分裂检测:从左到右扫描 列,维护三个布尔标志:
p1:是否已经遇到过有竖立球瓶的列。p0:在遇到竖立列之后,是否遇到过空列(所有球瓶倒下的列)。resp:在遇到空列之后,是否又遇到了竖立列。
状态转移逻辑:
- 当前列为竖立列(
col[i] == 1)且p1为假 → 首次遇到竖立列,设置p1 = true。 - 当前列为空列(
col[i] == 0)且p1为真 → 在竖立列之后遇到空列,设置p0 = true。 - 当前列为竖立列(
col[i] == 1)且p0为真 → 在空列之后再次遇到竖立列,满足分裂条件,设置resp = true。
这恰好对应了"两端竖立、中间有空列"的模式:
p1找到左端竖立列,p0找到中间空列,resp确认右端竖立列存在。
-
-
边界与细节:
- 球瓶 (
s[0])必须为'0',否则直接输出No。这是题目明确要求的第一个条件。 - 即使存在多组"分裂"模式,只要检测到一组即可输出
Yes。 - 列是从左到右扫描的,
p1→p0→resp的三段式检测天然保证了"中间列"在"两端列"之间。
- 球瓶 (
⏱️ 复杂度分析
- 时间复杂度:,输入始终为 个字符,遍历和扫描均为常数操作。
- 空间复杂度:,仅使用固定大小的数组
col[7]和几个布尔变量。
💻 标准代码 (C++)
#include<bits/stdc++.h> using namespace std; int main(){ string s; cin >> s; // 条件1:球瓶1必须倒下,否则直接输出No if(s[0] == '1'){ cout << "No"; return 0; } // map[i]:球瓶i+1所在的列编号(1~7) // 列1: 瓶7 | 列2: 瓶4 | 列3: 瓶2,8 | 列4: 瓶1,5 | 列5: 瓶3,9 | 列6: 瓶6 | 列7: 瓶10 int map[10] = {4, 3, 5, 2, 4, 6, 1, 3, 5, 7}; int col[7] = {0}; // 标记每列是否有竖立的球瓶 // 遍历所有球瓶,将竖立球瓶所在的列标记为1 for(int i = 0; i < 10; i++) if(s[i] == '1') col[map[i] - 1] = 1; // 三段式扫描检测分裂模式 bool p1 = false; // 是否遇到第一个竖立列 bool p0 = false; // 在竖立列之后是否遇到空列 bool resp = false; // 在空列之后是否又遇到竖立列(即是否构成分裂) for(int i = 0; i < 7; i++){ if(col[i] == 1 && p1 == false) p1 = true; // 发现左端竖立列 if(col[i] == 0 && p1 == true) p0 = true; // 发现中间空列 if(col[i] == 1 && p0 == true) resp = true; // 发现右端竖立列,满足分裂条件 } if(resp) cout << "Yes"; else cout << "No"; return 0; } -
- 1
信息
- ID
- 629
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 1
- 已通过
- 1
- 上传者