这个也只麻烦一点点而已,与easy version不同的地方在于允许3张连续的牌出现
进行这种判断只需要进行一遍DFS就行了
关键在于DFS的细节:
如果一张牌出现【超过或等于】3次,他都有可能凑成一个3张相同的坎牌,但也有可能不
如果一张牌出现【超过或等于】2次,他都有可能凑成一个对牌,但也有可能不
如果一张牌出现【超过或等于】1次,他都有可能凑成一个3张连续的坎牌,但也有可能不
如果一张牌出现【只有】1次,他【只可能】凑成一个3张连续的坎牌

所以在DFS实现过程中,我们要把每种情况尝试一遍,统计坎牌和对牌的出现次数

有一个特例:
1W1W2W2W3W3W4W4W5T6T6T7T7T8T
这里的1W2W3W4W四张牌均有2个相同,他们既有可能作为坎牌也有可能作为对牌
遇到这种情况,我们从小到大遍历时,优先考虑坎牌的情况(一点点贪心?不证明了,但应该是对的。)

核心代码用伪代码表示大概是

pair<int, int> get(int num[]) {
    int cnt2 = 0, cnt3 = 0, sum = 0;
    for(int i = 1; i <= 29; ++i)
        sum += num[i];
    for(int i = 1; i <= 29; ++i) {
        if(!num[i]) continue;
        switch(num[i]) {
            case 4:
            case 3:
                尝试用3张相同的牌作为坎牌
            case 2: {
                if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) {
                    尝试用3张连续的牌作为坎牌
                }
                尝试用2张相同的牌作为对牌
                break;
            }
            case 1: {
                if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) {
                    尝试用3张连续的牌作为坎牌
                }
                else
                    return make_pair(0, 0);
            }
        }
    }
    return make_pair(0, 0);
}

然后是完整代码

#include<bits/stdc++.h>
using namespace std;
int getId(char num, char type) {
    if(type == 'W')
        return num - '0';
    if(type == 'T')
        return num - '0' + 10;
    else
        return num - '0' + 20;
}
bool judge(int id, char type) {
    if(1 <= id && id <= 9 && type == 'W')
        return true;
    if(11 <= id && id <= 19 && type == 'T')
        return true;
    if(21 <= id && id <= 29 && type == 'S')
        return true;
    return false;
}
map<int, int> mp;
pair<int, int> get(int num[]) {
    int cnt2 = 0, cnt3 = 0, sum = 0;
    for(int i = 1; i <= 29; ++i)
        sum += num[i];
    for(int i = 1; i <= 29; ++i) {
        if(!num[i]) continue;
        switch(num[i]) {
            case 4:
            case 3: {
                num[i] -= 3; ++cnt3;

                pair<int, int> pr = get(num);
                cnt2 += pr.first;
                cnt3 += pr.second;
                if(2*cnt2 + 3*cnt3 == sum)
                    return make_pair(cnt2, cnt3);
                cnt2 -= pr.first;
                cnt3 -= pr.second;

                num[i] += 3; --cnt3;
            }
            case 2: {
                if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) {
                    --num[i]; --num[i+1]; --num[i+2]; ++cnt3;

                    pair<int, int> pr = get(num);
                    cnt2 += pr.first;
                    cnt3 += pr.second;
                    if(2*cnt2 + 3*cnt3 == sum)
                        return make_pair(cnt2, cnt3);
                    cnt2 -= pr.first;
                    cnt3 -= pr.second;

                    ++num[i]; ++num[i+1]; ++num[i+2]; --cnt3;
                }

                num[i] -= 2; ++cnt2;

                pair<int, int> pr = get(num);
                cnt2 += pr.first;
                cnt3 += pr.second;
                if(2*cnt2 + 3*cnt3 == sum)
                    return make_pair(cnt2, cnt3);
                cnt2 -= pr.first;
                cnt3 -= pr.second;

                num[i] += 2; --cnt2;
                break;
            }
            case 1: {
                if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) {
                    --num[i]; --num[i+1]; --num[i+2]; ++cnt3;

                    pair<int, int> pr = get(num);
                    cnt2 += pr.first;
                    cnt3 += pr.second;
                    if(2*cnt2 + 3*cnt3 == sum)
                        return make_pair(cnt2, cnt3);
                    cnt2 -= pr.first;
                    cnt3 -= pr.second;

                    ++num[i]; ++num[i+1]; ++num[i+2]; --cnt3;
                }
                else
                    return make_pair(0, 0);
            }
        }
    }
    return make_pair(0, 0);
}
pair<int, int> judge() {
    int num[30]; memset(num, 0, sizeof(num));
    for(int i = 1; i <= 29; ++i)
        num[i] = mp[i];
    pair<int, int> ans = get(num);
    return ans;
}
void printMap() {
    printf("=============\n");
    for(auto it = mp.begin(); it != mp.end(); ++it)
        printf("%d->%d\n", it->first, it->second);
    printf("=============\n");
}
int main() {
    int n;
    while(cin>>n) {
        char que; cin>>que;
        while(n--) {
            mp.clear();
            bool mark = true;
            char pai[50]; cin>>pai;
            for(int i = 0; i < 14; ++i) {
                int id = getId(pai[i*2], pai[i*2 + 1]);
                if(judge(id, que)) {
                    mark = false;
                    break;
                }
                mp[id]++;
            }

            if(mark) {
                pair<int, int> pr = judge();
                int cnt2 = pr.first;
                int cnt3 = pr.second;
                if(!(cnt2 == 7 || (cnt2 == 1 && cnt3 == 4)))
                    mark = false;
            }

            printf(mark ? "Yes\n" : "No\n");
        }
    }
    return 0;
}