“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于PAT的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
1. 字符串中必须仅有P, A, T这三种字符,不可以包含其它字符;
2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
3. 如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a, b, c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
现在就请你为PAT写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式:每个测试输入包含1个测试用例。第1行给出一个自然数n(<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过100,且不包含空格。
输出格式:每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出YES,否则输出NO。
输入样例:
8
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
初看题目我是这么理解的:
- 由条件 (1) (2) 知,有 2 种基本情况是 “正确” 的,即 PAT 和 xPATx;
- 由条件 (3) 知,其余 “正确” 情况都是由那 2 种基本情况不断演变而来。
因此我想到的是递归暴力法:
- 首先判断 2 种基本情况为 “正确”。
- 要想 aPbATca “正确”,就要 aPbTc “正确”,于是用 string.find() 找到 aPbATca 中 'P' 和 'AT' 的下标,通过 string.substr() 截取字符串获得 aPbTc,递归判断 aPbTc 是否 “正确”。
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 bool onlyA(string s) { 7 for (int i = 0; i < s.size(); i++) 8 if (s[i] != 'A') 9 return false; 10 return true; 11 } 12 13 bool isCorrect(string s) { 14 if (s == "PAT") return true; 15 else if (s.find("PAT") != string::npos) { 16 int idx = s.find("PAT"); 17 string x1 = s.substr(0, idx), x2 = s.substr(idx + 3); 18 if (onlyA(x1) && onlyA(x2) && x1 == x2) 19 return true; 20 } 21 else if (s.find("P") != string::npos) { 22 int p_idx = s.find("P"); 23 string a1 = s.substr(0, p_idx); 24 string a2 = s.substr(s.size() - p_idx); 25 if (onlyA(a1) && onlyA(a2) && a1 == a2 && s.find("AT") != string::npos) { 26 int at_idx = s.find("AT"); 27 string b = s.substr(p_idx + 1, at_idx - p_idx - 1); 28 string ca = s.substr(at_idx + 2); 29 string c = ca.substr(0, ca.size() - a2.size()); 30 if (isCorrect(a1 + "P" + b + "T" + c)) 31 return true; 32 } 33 else { 34 return false; 35 } 36 } 37 return false; 38 } 39 40 int main() { 41 int n; 42 cin >> n; 43 string *s = new string[n]; 44 for (int i = 0; i < n; i++) 45 cin >> s[i]; 46 for (int i = 0; i < n; i++) { 47 if (isCorrect(s[i])) 48 cout << "YES" << endl; 49 else 50 cout << "NO" << endl; 51 } 52 return 0; 53 }
后来查看网上解析,总结题意发现:
- 基本情况是 xPATx,x 只含有 'A' 或为空。这里我们用 a、b、c 表示原题中相应位置 'A' 的数量,则初始情况下,a = c,b = 1。
- 由条件(3),'P' 和 'T' 中间每增加 1 个 'A',即 b + 1 后,整个字符串结尾要添加 1 个 'P' 前的字符串,即 c 变为 c + a。
由初始状态 b = 1,且若 b = b + 1,则 c = c + a,可知 c = a × b。
挖掘到这个深层信息,改写 isCorrect() 函数如下,效率会更高。
// C style bool isCorrect(string s) { int a = 0, b = 0, c = 0; bool hasP = false, hasAT = false; for (int i = 0; i < s.size(); i++) { if (!hasP) { if (s[i] == 'A') { a++; continue; } else if (s[i] == 'P') { hasP = true; continue; } else { return false; } } else { if (!hasAT) { if (s[i] == 'A') { b++; continue; } else if (s[i] == 'T' && s[i - 1] == 'A') { hasAT = true; continue; } else { return false; } } else { if (s[i] == 'A') { c++; continue; } else { return false; } } } } if (hasP && hasAT && a * b == c) return true; else return false; } // C++ style bool isCorrect(string s) { int idxP = s.find("P"), idxAT = s.find("AT"); if (idxP != string::npos && idxAT != string::npos) { for (int i = 0; i < idxP; i++) { if (s[i] != 'A') return false; } for (int i = idxP + 1; i < idxAT; i++) { if (s[i] != 'A') return false; } for (int i = idxAT + 2; i < s.size(); i++) { if (s[i] != 'A') return false; } // a * b == c if (idxP * (idxAT - idxP) == (s.size() - idxAT - 2)) return true; } return false; }