1.題目
“答案正確”是自動判題系統給出的最令人歡喜的回覆。本題屬於 PAT 的“答案正確”大派送 —— 只要讀入的字串滿足下列條件,系統就輸出“答案正確”,否則輸出“答案錯誤”。
得到“答案正確”的條件是:
字串中必須僅有 P、 A、 T這三種字元,不可以包含其它字元;
任意形如 xPATx 的字串都可以獲得“答案正確”,其中 x 或者是空字串,或者是僅由字母 A 組成的字串;
如果 aPbTc 是正確的,那麼 aPbATca 也是正確的,其中 a、 b、 c 均或者是空字串,或者是僅由字母 A 組成的字串。
現在就請你為 PAT 寫一個自動裁判程式,判定哪些字串是可以獲得“答案正確”的。
輸入格式:
每個測試輸入包含 1 個測試用例。第 1 行給出一個正整數 n (≤10),是需要檢測的字串個數。接下來每個字串佔一行,字串長度不超過 100,且不包含空格。
輸出格式:
每個字串的檢測結果佔一行,如果該字串可以獲得“答案正確”,則輸出 YES,否則輸出 NO。
輸入樣例:
10
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
APATTAA
輸出樣例:
YES
YES
YES
YES
NO
NO
NO
NO
NO
NO
2.題解
2.1 數學推理
思路
1.任意形如 xPATx 的字串都可以獲得“答案正確”,其中 x 或者是空字串,或者是僅由字母 A 組成的字串;
那麼正確的有這些:
PAT
APATA
AAPATAA
AAAPATAAA
…不說了,就是中間一個A左右加上等量的A(不加也行)都是正確的。
也就是說,在不觸發做法2的情況下,前面的A個數和後面的A個數應該是相等的!!!
2.如果 aPbTc 是正確的,那麼 aPbATca 也是正確的,其中 a, b, c 均或者是空字串,或者是僅由字母 A 組成的字串。
拿上面的那幾個正確的舉例子,那麼正確的有這些:
PAT —— 對於 aPbTc 來說ac是空,b是A。所以 PAAT 是正確的。同理PAAAAAT中間加多少個A都是正確噠~
APATA —— 對於aPbTc來說,abc都是A。所以 APAATAA 是正確的。再類推一下,那麼 APAAATAAA 是正確的。
AAPATAA —— 對於aPbTc來說,a和c是AA,b是A。所以AAPAATAAAA是正確的,再類推一下,AAPAAATAAAAAA 是正確的~~
所以說規律就是,可以在P和T中間加A並且在T後面加A,要求必須是,中間加上一個A,末尾就得加上幾倍的(P前面A的那個字串)。
換句話說就是,中間的A的個數如果是3,那麼末尾的A的個數就得是開頭A的個數的3倍。很巧,當中間A為一個的時候,末尾和開頭A的個數必須相等正好是第二條的要求~
很簡單的道理,開始時必定有前方A的個數等於後方A的個數, 後面中間每加上一個A, 後方都要加上一倍前方A的數量 ==> 中間新增A的個數 * 前方A的個數 = 結尾新增A的個數; 又因為剛開始中間有一個A, 而且末尾A的個數 = 開頭A的個數
我們由 開頭A的個數 * 中間開始的一個A = 原有結尾A的個數 與 開頭A的個數 * 中間新增A的個數 = 結尾新增A的個數; 可以推出 開頭A的個數 * (中間開始A的個數 + 中間開始的一個A) = (原有結尾A的個數 + 結尾新增A個數)
3.即新的式子滿足: 開頭A的個數 * 中間A的個數 = 結尾A的個數 (且中間至少有一個A)!!!!!
程式碼
#include <iostream>
#include <map>
using namespace std;
int main() {
int n, p = 0, t = 0;
string s;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> s;
map<char, int> m;
// 記錄三個字串出現次數 和 P與T的出現位置
for(int j = 0; j < s.size(); j++) {
m[s[j]]++;
if (s[j] == 'P') p = j;
if (s[j] == 'T') t = j;
}
// 滿足P和T必須要一個且僅有一個,且A個數不為0,即雜湊表存了3個char鍵值; 且P和T不能是相鄰狀態,即中間至少隔了一個A, 且個數方面滿足上面的要求
if (m['P'] == 1 && m['A'] != 0 && m['T'] == 1 && m.size() == 3 && t-p != 1 && p * (t-p-1) == s.length()-t-1)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
2.2 使用正規表示式
思路
同2.1
程式碼
#include<bits/stdc++.h>
using namespace std;
bool isValidPATString(const string& s) {
// 定義正規表示式,匹配模式為 (A*)P(A+)T(A*)
// R表示可以不需要轉義就能使用跳脫字元, ()括起來的可以被smatch捕獲存進match陣列中
regex pattern(R"((A*)P(A+)T(A*))");
//regex pattern("(A*)P(A+)T(A*)"); //普通字串字面量
smatch match;
// 使用 regex_match 進行匹配,並將結果儲存在 match 中
if (regex_match(s, match, pattern)) {
// 獲取匹配的各部分字串
string preA = match[1].str();
string midA = match[2].str();
string postA = match[3].str();
// 計算各部分的長度
int preACount = preA.length();
int midACount = midA.length();
int postACount = postA.length();
// 檢查 preA 的長度乘以 midA 的長度是否等於 postA 的長度
if (preACount * midACount == postACount) {
return true;
}
}
return false;
}
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++){
string str;
cin >> str;
if(isValidPATString(str)){
cout << "YES" << endl;
} else{
cout << "NO" << endl;
}
}
return 0;
}