PAT 乙级题目讲解:1003《我要通过!》
·
✅ PAT 乙级题目讲解:1003《我要通过!》
🧩 题目简介
本题属于字符串合法性判断问题,题目要求根据字符串的结构判断其是否为一个“正确”的字符串。所谓“正确”,是指字符串满足某种特定的格式,由字符 P、A、T 组成,且要满足一系列生成规则。
我们需要判断每一个字符串是否满足如下条件:
- 只能包含字符
P、A、T; - 且仅出现一次
P和一次T,且P必须出现在T之前; - 将字符串表示为
aPbTc的形式,且中间部分(即b)长度至少为 1,并满足公式:len(a) * len(b) == len(c)。
🧪 样例分析
输入:
10
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
PTAA
逐个分析如下:
PAT:len(a)=0,len(b)=1,len(c)=0⇒0×1=0✅PAAT:len(a)=0,len(b)=2,len(c)=0⇒0×2=0✅AAPATAA:len(a)=2,len(b)=1,len(c)=2⇒2×1=2✅AAPAATAAAA:len(a)=2,len(b)=2,len(c)=4⇒2×2=4✅xPATx:含非法字符 ❌PT:中间无A⇒len(b)=0❌Whatever:含非法字符 ❌APAAATAA:len(a)=1,len(b)=3,len(c)=2⇒1×3≠2❌APT:中间无A❌PTAA:多个T❌
因此输出为:
YES
YES
YES
YES
NO
NO
NO
NO
NO
NO
数学推导:为何 lena * lenb == lenc
我们设一个基础合法串为 PAT,其中 len(a)=0,len(b)=1,len(c)=0,此时 0 × 1 = 0 成立。
考虑生成新串的过程,每次在中段 b 末尾增加一个 A,同时在尾部 c 增加一段等长的 A。我们来推导该规则的数学本质:
设:
- 初始时:
len(a) = na,len(b) = nb = 1,len(c) = nc = na - 每次扩展中段
b增加一个A,变成nb + m - 同时末尾
c要扩展为:nc + m × na(每次扩展b,就多加一段a的长度)
于是:
最终的中段长度:len(b) = nb + m
最终的尾段长度:len(c) = nc + m × na = na + m × na = na × (1 + m)
此时:
len(b) = 1 + m
len(c) = na × (1 + m)
所以有:
len(a) × len(b) = na × (1 + m) = len(c)
因此,所有由基本串扩展得到的串都满足:
len(a) × len(b) == len(c)
这个公式正是我们在程序中进行判断的关键逻辑。
🔍 解题思路
📎 变量说明
| 变量名 | 含义 |
|---|---|
n |
测试用例数量 |
s |
当前待检测的字符串 |
p |
字符 P 所在的位置 |
t |
字符 T 所在的位置 |
cp |
字符 P 出现次数 |
ct |
字符 T 出现次数 |
lena |
P 左侧 A 的个数 |
lenb |
P 和 T 之间 A 的个数 |
lenc |
T 右侧 A 的个数 |
✅ Step 1:过滤非法字符
遍历字符串中所有字符,若出现非 P、A、T 以外的字符,立即判为非法。
for(int i = 0; i < len; i++){
if(s[i] != 'P' && s[i] != 'A' && s[i] != 'T'){
f = 0;
break;
}
}
✅ Step 2:统计 P、T 出现次数及位置
确保 P 和 T 各自出现且仅出现一次,且 P 必须在 T 之前。
if(cp != 1 || ct != 1 || p >= t) f = 0;
✅ Step 3:根据公式判断是否合法
将字符串分段后,统计三部分 A 的数量,判断是否满足 lena * lenb == lenc 且 lenb > 0。
int lena = p;
int lenb = t - p - 1;
int lenc = len - t - 1;
if(!lenb || lena * lenb != lenc) f = 0;
完整代码
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int main(){
cin >> n;
while(n--){
cin >> s;
int len = s.size();
bool f = 1;
// 1. 只有 P A T
int p, t, cp = 0, ct = 0;
for(int i = 0; i < len; i++){
if(s[i] != 'P' && s[i] != 'A' && s[i] != 'T'){
f = 0;
break;
}
if(s[i] == 'P'){
cp++;
p = i;
}
if(s[i] == 'T'){
ct++;
t = i;
}
}
// 2. P 和 T 唯一,且 P 先于 T
if(cp != 1 || ct != 1 || p >= t) f = 0;
// 3. aPbTc -> lenb >= 1 且 lena * lenb = lenc
int lena = p;
int lenb = t - p - 1;
int lenc = len - t - 1;
if(!lenb || lena * lenb != lenc) f = 0;
if(f) cout << "YES";
else cout << "NO";
if(n > 0) cout << "\n";
}
return 0;
}
🚧 常见错误提醒
| 错误类型 | 具体表现 |
|---|---|
| 字符合法性错误 | 包含 P、A、T 以外的字符 |
P、T 多次出现 |
cp != 1 或 ct != 1 |
P 在 T 之后 |
p >= t |
中间部分无 A |
lenb == 0 |
| 数学公式不成立 | lena * lenb != lenc |
| 输出格式错误 | 多输出换行或少输出换行 |
✅ 总结归纳
- 本题是构造字符串合法性判断的经典题型。
- 推导出公式
lena * lenb == lenc是解题核心。 - 熟练处理字符串分段,逻辑判断,数学建模。
🧠 思维拓展
- 本题可延展到“语言生成规则”建模、“有限状态机”合法串识别问题。
- 可作为学习自底向上归纳规则的入门训练题。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)