1 条题解

  • 0
    @ 2026-6-17 18:00:03

    题意

    • 进行 T 组询问
    • 每组询问,给定 n 张牌,问是否可以两次以内出完(一次或者两次)
    • 每次出牌有三种牌型可以选择
      • 顺子:选择从小到大连续的至少 3 张牌打出
      • 三带二:选择一种牌 a 和另一种牌 b,打出 3 张 a 和 2 张 b
      • 四带一一:选择一种牌 a 和另一种牌 b,以及与 a b 不同的牌 c,打出 4 张 a、1 张 b 和 1 张 c
    • 如果可以两次内出完,输出 Yes,按格式输出每次打出牌的类型
      • 输出第一行一个整数 1 或者 2,表示出牌次数
      • 接着输出每次出牌的内容
      • 顺子,输出 S 表示顺子,然后输出 m a1 a2 ... am 表示出了 m 张牌作为顺子且他们从小到大依次是哪些
      • 三带二,输出 T 表示三带二,然后输出 a b 表示出了 3 张 a 和 2 张 b
      • 四带一一,输出 F 表示四带一一,然后输出 a b c 表示出 4 张 a、1 张 b 和 1 张 c
    • 如果不可以两次内出完,输出 No
    • 值得注意的是有 13 种牌 2 3 4 5 6 7 8 9 T J Q K A 依次代表点数 2 ~ 14(其中 A 不能表示 1)
    • 且不会有某种牌出现次数超过 4

    思路

    • 没什么思路,直接模拟

    数据范围

    • 对于测试点 1 ~ 15 (30 分)
      • 数据保证有解,且存在一次出完的方式
      • 思路为,直接判断是哪种牌型,组织对应牌型输出即可
    • 对于测试点 12 ~ 27
      • 没有特殊解法,可以用于检测哪种牌型判断错误

    题解

    • 实际上总共只有 13 种牌
      • 所以顺子只有 C1321312C_{13}^2 - 13 - 12 种牌型
      • 三带二只有 A132A_{13}^2 种牌型
      • 四带一一有 C133×C31C_{13}^3 \times C_3 ^ 1 种牌型
      • 这里合法的方案只有 1080
    • 所以可以有一个 108021080^2 的做法
      • 枚举第一种牌型
      • 然后枚举第二种牌型
      • 最后判定两种牌型的选取牌的集合是否恰好为输入的牌
    • 能够获得 9090 分,因为效率问题,最后 10 分得不到
    • 效率的解决方式
      • 方式一(下面 code 的方式)
        • 对于所有的一次和两次的合法出法,提前计算它的答案
        • 然后对于输入直接在预处理的答案中查询即可
        • 时间复杂度:$O(1080^2\times 13 \times \log 1080^2 + T\times n \times \log 1080^2)$
        • 实际上中间的 13 和 n 倍数是卡在字符串比较上,但事实上并不会全量比较(只会前缀比较)
      • 方法二
        • 提前只预处理出一次合法的情况,提前计算它的答案
        • 对于每次询问,先枚举上面的所有 1080 种合法情况,扣除这些牌
        • 在检查剩下的牌是否是合法情况即可
        • 时间复杂度:$O(1080\times 13 \times \log 1080 + T\times (1080 \times 13 + 13 \times \log 1080))$

    code

    map<string, string> ma;
    void solved() {
    	
    	int n;	cin >> n;
    	string s;
    	_for(i, 1, n) {
    		char c;	cin >> c;
    		s += c;
    	}
    	sort(s.begin(), s.end());
    	if(ma[s] == "") cout << "No" << endl;
    	else cout << ma[s];
    	
    	return ;
    }
    string hs[13 * 13 * 2 + 13 * 13 * 13 + 9];
    int tot;
    string ask(string s) {
    	string ans = "";
    	if(s[0] == '*') {
    		ans = "S " + to_string(s.size() - 1);
    		_for(i, 1, s.size() - 1) ans = ans + " " + s[i];
    	} else if(s.size() == 5) ans = ans + "T " + s[0] + " " + s[4];
    	else ans = ans + "F " + s[0] + ' ' + s[4] + ' ' + s[5];
    	ans += '\n';
    	return ans;
    }
    void init() {
    	string s = "  23456789TJQKA";
    	int n = 14;
    	_for(l, 2, n) _for(r, l + 2, n) {
    		string now = "*";
    		_for(i, l, r) now += s[i];
    		hs[++ tot] = now;
    	}
    	_for(i, 2, n) _for(j, 2, n) if(i != j) {
    		string now = "";
    		_for(k, 1, 3) now += s[i];
    		_for(k, 1, 2) now += s[j];
    		hs[++ tot] = now;
    	}
    	_for(i, 2, n) _for(j, 2, n) _for(k, j + 1, n) if(i != j && i != k) {
    		string now = "";
    		_for(t, 1, 4) now += s[i];
    		now += s[j], now += s[k];
    		hs[++ tot] = now;
    	}
    	_for(i, 1, tot) {
    		string now = "";
    		if(hs[i][0] == '*') now = hs[i].substr(1);
    		else now = hs[i];
    		sort(now.begin(), now.end());
    		string ans = "Yes\n1\n";
    		ma[now] = ans + ask(hs[i]);
    	}
    	_for(i, 1, tot) _for(j, i, tot) {
    		string now = "";
    		if(hs[i][0] == '*') now += hs[i].substr(1);
    		else now += hs[i];
    		if(hs[j][0] == '*') now += hs[j].substr(1);
    		else now += hs[j];
    		sort(now.begin(), now.end());
    		string ans = "Yes\n2\n" + ask(hs[i]) + ask(hs[j]);
    		ma[now] = ans;
    	}
    }
    signed main() {
    	IOS	PCS(6)
    	init();
    	int ttx;  cin >> ttx;  _for(i, 1, ttx) 
    		solved();
    	return 0;
    }
    

    另一种做法

    #include <bits/stdc++.h>
    using namespace std;
    typedef array<int, 13> card;
    string id = "23456789TJQKA";
    map<card, string> mp;
    int main() 
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        for (int m = 0; m < 13 * 13 * 13 * 3; m++) {
            int type = m / 2197;
            int r = m % 2197;
            int i = r % 13;
            int j = (r / 13) % 13;
            int k = r / 169;
            if (type == 0 && i + j + 3 <= 13 && !k) {
                card h{};
                string s = "S " + to_string(j + 3);
                for (int x = 0; x < j + 3; x++) {
                    h[i + x] = 1;
                    s += string(" ") + id[i + x];
                }
                mp[h] = s;
            }
            if (type == 1 && i != j && !k) {
                card h{};
                h[i] = 3;
                h[j] = 2;
                mp[h] = string("T ") + id[i] + " " + id[j];
            }
            if (type == 2 && i != j && i != k && j < k) {
                card h{};
                h[i] = 4;
                h[j] = 1;
                h[k] = 1;
                mp[h] = string("F ") + id[i] + " " + id[j] + " " + id[k];
            }
        }
        int T;
        cin >> T;
        while (T--) {
            int n;
            cin >> n;
            card c{};
            for (int i = 0; i < n; i++) {
                char ch;
                cin >> ch;
                c[id.find(ch)]++;
            }
            if (mp.count(c)) {
                cout << "Yes\n1\n" << mp[c] << "\n";
                continue;
            }
            string s1 = "";
            for (auto p : mp) {
                auto r = c;
                bool ok = 1;
                for (int i = 0; i < 13; i++) {
                    if ((r[i] -= p.first[i]) < 0) {
                        ok = 0;
                    }
                }
                if (ok && mp.count(r)) {
                    s1 = p.second + "\n" + mp[r];
                    break;
                }
            }
            if (s1 != "") {
                cout << "Yes\n2\n" << s1 << "\n";
            } else {
                cout << "No\n";
            }
        }
    }
    
    • 1

    信息

    ID
    159
    时间
    1000ms
    内存
    256MiB
    难度
    3
    标签
    递交数
    18
    已通过
    2
    上传者