浙大PAT刷題-1003.我要透過!!!

DawnTraveler發表於2024-05-24

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;
}

相關文章