扑克

GitHub跳转原题关系图返回列表

预处理全排列合法5张牌组合,按牌力排序建立3张牌到合法方案索引,询问时二分找恰好能胜的最弱组合。

OJ: roj

题目 ID: 10019

难度:提高+/省选-

标签:模拟二分

创建: 2026-10-10 07:13

更新: 2026-10-10 07:13

形式化题目

有一副 52 张扑克牌(2~A,共 4 种花色)。定义 5 张牌的牌力大小规则: 同花顺 > 四条 > 葫芦 > 同花 > 顺子 > 三条 > 其它(本题中任意 3 张牌都可通过补齐 2 张组成三条及以上的牌型)。 牌型一致时按关键牌点数进行比较。若点数一致比较关键牌花色,黑桃 > 红桃 > 梅花 > 方块。 游戏判断胜负时只看牌型与点数,点数完全相同时算平局。

给定鸡尾酒和智乃的手牌(各 3 张,按升序排列),每人可以在其余 52 张牌内任意想象出 2 张,组成 5 张最大牌型的牌。 现在求:在智乃按最优策略组出最大 5 张牌的基础上,鸡尾酒是否能组出在“游戏胜负判定(不看花色)”中严格大过智乃的 5 张牌?如果能,鸡尾酒应输出满足该条件中“牌力(含花色判定)最弱”的一组牌以刚好稳赢。否则输出 -1。

正解

思路

本题具有极强的预处理特性:如果直接用深搜对每次查询枚举 2 张牌凑 5 张然后判断,在 T≤100000T \le 100000 的情况下必然会超时。

注意到,从 52 张牌中任意抽取 5 张的总方案数为 (525)=2,598,960\binom{52}{5} = 2,598,960 种。这个数量级足以在预处理阶段进行遍历。不仅如此,由于任何给定的 3 张牌至少可以凑出“三条”(只需任取自己的一张牌对应的其他两张同点数牌),所以作为“最强牌”,所有的“高牌”、“一对”、“两对”等弱牌型均不可能成为答案,可以在预处理时直接滤除。 过滤后,合法的 5 张牌组合仅剩 73,608 种。

具体做法如下:

  1. 全集枚举与牌型判定:在预处理阶段,从 52 张牌中循环选出 5 张牌。编写鉴别函数确认是否属于(同花顺、四条、葫芦、同花、顺子、三条)中的一种。如果属于,则将 5 张牌按牌型的关键比较顺序分配到 f0 到 f4 比较位中。
  2. 全局排序:将这 7 万多种合法牌组统一进行排序。排序规则按照题意“先牌型,后各比较位点数,最后各比较位花色”降序排列(最强的牌排在数组最前)。
  3. 构建三张牌的反向索引:对于每一组强牌组(包含 5 张牌),从中选出任意 3 张牌(共 (53)=10\binom{5}{3} = 10 种取法)。将该组牌的索引 i 存入到这 3 张牌组合构成的 vector 数组里。由于循环加入的顺序不变,这个 vector 内部,保存的索引 i 是天然有序(牌力从强到弱降序)的。
  4. 单次查询:根据智乃的三张牌找到其最强牌(即对应 vector 中的第 0 位)。随后在鸡尾酒的三张牌对应的 vector 中,通过倍增二分法寻找满足“仅比较牌型与点数即可严格大过智乃”的最后一个元素(即牌力最弱的一组以满足“刚好稳赢”)。

代码

python
#!/usr/bin/env python3
# Author: Antigravity
# Date: 2026-10-10 05:00
# 10019 扑克:预处理合法 5 张牌组 -> 按牌力排序 -> 三张子集反向索引 -> 二分找最弱稳赢组合。

import sys
import itertools

def solve() -> None:
    # ① 牌型表:同花顺 2 > 四条 3 > 葫芦 4 > 同花 5 > 顺子 6 > 三条 7
    #    f 是 5 个比较位,f[4] 最重要
    input_data = sys.stdin.read().split()
    if not input_data:
        return
    
    d_val = tuple((x - 1) // 4 for x in range(53))
    hua_val = tuple((x - 1) % 4 for x in range(53))
    
    arr = []
    
    for p in itertools.combinations(range(1, 53), 5):
        p0, p1, p2, p3, p4 = p
        d0, d1, d2, d3, d4 = d_val[p0], d_val[p1], d_val[p2], d_val[p3], d_val[p4]
        t0, t1, t2, t3, t4 = hua_val[p0], hua_val[p1], hua_val[p2], hua_val[p3], hua_val[p4]
        
        is_flush = (t0 == t1 and t1 == t2 and t2 == t3 and t3 == t4)
        is_straight = (d0 + 1 == d1 and d1 + 1 == d2 and d2 + 1 == d3 and d3 + 1 == d4)
        
        tp = 0
        f = None
        
        if is_straight and is_flush:
            tp = 2
            f = (p0, p1, p2, p3, p4)
        elif d0 == d1 and d1 == d2 and d2 == d3:
            tp = 3
            f = (p4, p0, p1, p2, p3)
        elif d1 == d2 and d2 == d3 and d3 == d4:
            tp = 3
            f = (p0, p1, p2, p3, p4)
        elif d0 == d1 and d1 == d2 and d3 == d4:
            tp = 4
            f = (p3, p4, p0, p1, p2)
        elif d0 == d1 and d2 == d3 and d3 == d4:
            tp = 4
            f = (p0, p1, p2, p3, p4)
        elif is_flush:
            tp = 5
            f = (p0, p1, p2, p3, p4)
        elif is_straight:
            tp = 6
            f = (p0, p1, p2, p3, p4)
        elif d0 == d1 and d1 == d2:
            tp = 7
            f = (p3, p4, p0, p1, p2)
        elif d1 == d2 and d2 == d3:
            tp = 7
            f = (p0, p4, p1, p2, p3)
        elif d2 == d3 and d3 == d4:
            tp = 7
            f = (p0, p1, p2, p3, p4)
            
        if tp != 0:
            arr.append((tp, f, p))
            
    def sort_key(item):
        tp, f, _ = item
        return (
            tp,
            -d_val[f[4]], -d_val[f[3]], -d_val[f[2]], -d_val[f[1]], -d_val[f[0]],
            hua_val[f[4]], hua_val[f[3]], hua_val[f[2]], hua_val[f[1]], hua_val[f[0]]
        )
        
    arr.sort(key=sort_key)

    # ② 每组牌登记到 10 个三张子集桶里(桶内天然按牌力降序)
    a = [[] for _ in range(150005)]
    for idx, item in enumerate(arr):
        p = item[2]
        for c_comb in itertools.combinations(p, 3):
            h = c_comb[0] * 2809 + c_comb[1] * 53 + c_comb[2]
            a[h].append(idx)
            
    def parse_card(s):
        tt = {'S':1, 'H':2, 'C':3, 'D':4}[s[0]]
        if '2' <= s[1] <= '9': qq = int(s[1])
        elif s[1] == 'T': qq = 10
        elif s[1] == 'J': qq = 11
        elif s[1] == 'Q': qq = 12
        elif s[1] == 'K': qq = 13
        elif s[1] == 'A': qq = 14
        return (qq - 2) * 4 + tt
        
    def out_card(p):
        # 与官方 std.cpp 一致:每张牌后跟一个空格
        res = []
        for x in p:
            h = hua_val[x]
            dv = d_val[x]
            res.append("SHCD"[h] + "23456789TJQKA"[dv] + " ")
        return "".join(res)
        
    def cmp2_is_1(x_idx, y_idx):
        x_tp, x_f, _ = arr[x_idx]
        y_tp, y_f, _ = arr[y_idx]
        if x_tp != y_tp:
            return x_tp < y_tp
        for i in range(4, -1, -1):
            dx = d_val[x_f[i]]
            dy = d_val[y_f[i]]
            if dx != dy:
                return dx > dy
        return False

    idx_data = 0
    T = int(input_data[idx_data])
    idx_data += 1
    
    out_lines = []
    for _ in range(T):
        if idx_data + 6 > len(input_data):
            break
        s = input_data[idx_data:idx_data+6]
        idx_data += 6
        
        c_cocktail = [parse_card(x) for x in s[0:3]]
        c_chino = [parse_card(x) for x in s[3:6]]
        
        h_x = c_cocktail[0] * 2809 + c_cocktail[1] * 53 + c_cocktail[2]
        h_y = c_chino[0] * 2809 + c_chino[1] * 53 + c_chino[2]
        
        if not a[h_y]:
            out_lines.append("-1")
            continue
            
        y_max = a[h_y][0]
        if not a[h_x] or not cmp2_is_1(a[h_x][0], y_max):
            out_lines.append("-1")
            continue

        # ③ 倍增二分:求最后一个仍能赢的(牌力最弱)
        now = 0
        siz = len(a[h_x])
        for j in (4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1):
            if now + j < siz and cmp2_is_1(a[h_x][now + j], y_max):
                now += j
                
        best_p = arr[a[h_x][now]][2]
        out_lines.append(out_card(best_p))
        
    print('\n'.join(out_lines))

if __name__ == '__main__':
    solve()
cpp
/*
 * Author: Antigravity
 * Date: 2026-10-10 05:00
 *
 * 10019 扑克:预处理全部合法 5 张牌组 → 按牌力升序排序 → 对每组牌的 10 个
 * 三张子集建反向索引 → 询问时二分找「刚好能赢智乃最强牌」的最弱组合。
 */
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

typedef long long ll;

struct nod {
    short p[5];
    short tp;
    short f[5];
};

nod arr[100005];
int tot = 0;
vector<int> a[150005];

int hua(int x) { return (x - 1) % 4; }
int d(int x) { return (x - 1) / 4; }

// 枚举牌型:同花顺 2 > 四条 3 > 葫芦 4 > 同花 5 > 顺子 6 > 三条 7
// f[4]..f[0] 是比较次序(f[4] 最重要)
void work(nod &now) {
    int p0 = now.p[0], p1 = now.p[1], p2 = now.p[2], p3 = now.p[3], p4 = now.p[4];
    int t0 = hua(p0), t1 = hua(p1), t2 = hua(p2), t3 = hua(p3), t4 = hua(p4);
    int d0 = d(p0), d1 = d(p1), d2 = d(p2), d3 = d(p3), d4 = d(p4);

    bool is_flush = (t0 == t1 && t1 == t2 && t2 == t3 && t3 == t4);
    bool is_straight = (d0 + 1 == d1 && d1 + 1 == d2 && d2 + 1 == d3 && d3 + 1 == d4);

    if (is_straight && is_flush) {
        now.tp = 2; now.f[0] = p0; now.f[1] = p1; now.f[2] = p2; now.f[3] = p3; now.f[4] = p4; return;
    }
    if (d0 == d1 && d1 == d2 && d2 == d3) {
        now.tp = 3; now.f[0] = p4; now.f[1] = p0; now.f[2] = p1; now.f[3] = p2; now.f[4] = p3; return;
    }
    if (d1 == d2 && d2 == d3 && d3 == d4) {
        now.tp = 3; now.f[0] = p0; now.f[1] = p1; now.f[2] = p2; now.f[3] = p3; now.f[4] = p4; return;
    }
    if (d0 == d1 && d1 == d2 && d3 == d4) {
        now.tp = 4; now.f[0] = p3; now.f[1] = p4; now.f[2] = p0; now.f[3] = p1; now.f[4] = p2; return;
    }
    if (d0 == d1 && d2 == d3 && d3 == d4) {
        now.tp = 4; now.f[0] = p0; now.f[1] = p1; now.f[2] = p2; now.f[3] = p3; now.f[4] = p4; return;
    }
    if (is_flush) {
        now.tp = 5; now.f[0] = p0; now.f[1] = p1; now.f[2] = p2; now.f[3] = p3; now.f[4] = p4; return;
    }
    if (is_straight) {
        now.tp = 6; now.f[0] = p0; now.f[1] = p1; now.f[2] = p2; now.f[3] = p3; now.f[4] = p4; return;
    }
    if (d0 == d1 && d1 == d2) {
        now.tp = 7; now.f[0] = p3; now.f[1] = p4; now.f[2] = p0; now.f[3] = p1; now.f[4] = p2; return;
    }
    if (d1 == d2 && d2 == d3) {
        now.tp = 7; now.f[0] = p0; now.f[1] = p4; now.f[2] = p1; now.f[3] = p2; now.f[4] = p3; return;
    }
    if (d2 == d3 && d3 == d4) {
        now.tp = 7; now.f[0] = p0; now.f[1] = p1; now.f[2] = p2; now.f[3] = p3; now.f[4] = p4; return;
    }
    now.tp = 0;
}

// 含花色的完整比较(用于给全体牌组排序)
bool cmp(const nod &x, const nod &y) {
    if (x.tp != y.tp) return x.tp < y.tp;
    for (int i = 4; i >= 0; i--) {
        if (d(x.f[i]) != d(y.f[i])) return d(x.f[i]) > d(y.f[i]);
    }
    for (int i = 4; i >= 0; i--) {
        if (hua(x.f[i]) != hua(y.f[i])) return hua(x.f[i]) < hua(y.f[i]);
    }
    return false;
}

// 只看牌型与点数(题目胜负判定不看花色)
bool cmp2(const nod &x, const nod &y) {
    if (x.tp != y.tp) return x.tp < y.tp;
    for (int i = 4; i >= 0; i--) {
        if (d(x.f[i]) != d(y.f[i])) return d(x.f[i]) > d(y.f[i]);
    }
    return false;
}

char ch[15] = "23456789TJQKA";
char ch2[15] = "SHCD";

// 输出牌面:与官方 std.cpp 一致,每张牌后跟一个空格
void out(const nod &x) {
    for (int i = 0; i < 5; i++) {
        cout << ch2[hua(x.p[i])] << ch[d(x.p[i])] << " ";
    }
    cout << "\n";
}

int get_card() {
    string s;
    cin >> s;
    if (s.empty()) return 0;
    int tt = 0, qq = 0;
    if (s[0] == 'S') tt = 1;
    else if (s[0] == 'H') tt = 2;
    else if (s[0] == 'C') tt = 3;
    else if (s[0] == 'D') tt = 4;
    
    if (s[1] >= '2' && s[1] <= '9') qq = s[1] - '0';
    else if (s[1] == 'T') qq = 10;
    else if (s[1] == 'J') qq = 11;
    else if (s[1] == 'Q') qq = 12;
    else if (s[1] == 'K') qq = 13;
    else if (s[1] == 'A') qq = 14;
    return (qq - 2) * 4 + tt;
}

int get_hash(int x, int y, int z) {
    return x * 53 * 53 + y * 53 + z;
}

void solve() {
    // ① 枚举全部 C(52,5) 组合,只保留同花顺/四条/葫芦/同花/顺子/三条(共 73608 组)
    for (int i = 1; i <= 52; i++) {
        for (int j = i + 1; j <= 52; j++) {
            for (int k = j + 1; k <= 52; k++) {
                for (int t = k + 1; t <= 52; t++) {
                    for (int q = t + 1; q <= 52; q++) {
                        tot++;
                        arr[tot].p[0] = i; arr[tot].p[1] = j; arr[tot].p[2] = k;
                        arr[tot].p[3] = t; arr[tot].p[4] = q;
                        work(arr[tot]);
                        if (arr[tot].tp == 0) {
                            tot--;
                        }
                    }
                }
            }
        }
    }
    sort(arr + 1, arr + tot + 1, cmp);

    // ② 每组牌有 10 个三张子集,把它们登记到 a[三张牌 hash] 里(天然按牌力降序)
    for (int i = 1; i <= tot; i++) {
        a[get_hash(arr[i].p[0], arr[i].p[1], arr[i].p[2])].push_back(i);
        a[get_hash(arr[i].p[0], arr[i].p[1], arr[i].p[3])].push_back(i);
        a[get_hash(arr[i].p[0], arr[i].p[1], arr[i].p[4])].push_back(i);
        a[get_hash(arr[i].p[0], arr[i].p[2], arr[i].p[3])].push_back(i);
        a[get_hash(arr[i].p[0], arr[i].p[2], arr[i].p[4])].push_back(i);
        a[get_hash(arr[i].p[0], arr[i].p[3], arr[i].p[4])].push_back(i);
        a[get_hash(arr[i].p[1], arr[i].p[2], arr[i].p[3])].push_back(i);
        a[get_hash(arr[i].p[1], arr[i].p[2], arr[i].p[4])].push_back(i);
        a[get_hash(arr[i].p[1], arr[i].p[3], arr[i].p[4])].push_back(i);
        a[get_hash(arr[i].p[2], arr[i].p[3], arr[i].p[4])].push_back(i);
    }

    int q_val;
    if (!(cin >> q_val)) return;
    while (q_val--) {
        int X = get_card();
        X = X * 53 + get_card();
        X = X * 53 + get_card();

        int Y = get_card();
        Y = Y * 53 + get_card();
        Y = Y * 53 + get_card();

        if (a[Y].empty()) {
            cout << -1 << "\n";
            continue;
        }
        int y_best = a[Y][0];
        
        // ③ 连自己最强的牌都赢不了就直接 -1
        if (a[X].empty() || !cmp2(arr[a[X][0]], arr[y_best])) {
            cout << -1 << "\n";
            continue;
        }

        int now = 0;
        int siz = (int)a[X].size();
        // ④ 倍增二分:找最后一个仍能赢的(牌力最弱)组合
        for (int j = 1 << 12; j >= 1; j >>= 1) {
            if (now + j < siz && cmp2(arr[a[X][now + j]], arr[y_best])) {
                now += j;
            }
        }
        out(arr[a[X][now]]);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    solve();
    return 0;
}

复杂度

  • 时间复杂度:
    • 预处理:需要遍历 2,598,9602,598,960 种组合,每种组合 O(1)\mathcal{O}(1) 判定,并对符合的 7 万元素进行排序,时间复杂度大约 O((525)+Klog⁡K)\mathcal{O}(\binom{52}{5} + K \log K),其中 K≈7.3×104K \approx 7.3 \times 10^4,极为快速。
    • 单次查询:映射 hash 后进行 log⁡K\log K 次比较。总查询 O(Tlog⁡K)\mathcal{O}(T \log K)。整体时间常数极小,可通过。
  • 空间复杂度:
    • 需要存储 7 万种牌型,以及包含大约 7.3×1057.3 \times 10^5 个整形索引的 vector 数组。总内存占用约数 MB,O(K)\mathcal{O}(K)。

总结

  • 完整推导与约定 (T67清单):
    • 循环结构:包含单测数量 TT,while(T--) 循环处理。
    • 变量参与:所有的输入手牌都被映射计算,没有无用变量。
    • 输入格式:两位字符组合:首字母代表花色 S/H/C/D,第二位代表点数 2~9, T, J, Q, K, A。
    • 输出格式:输出 5 张字符串手牌以空格相隔,找不到解时输出一行 -1。
    • 边界与 UB:当鸡尾酒即使选出自己最强的牌都无法严格在点数上战胜智乃时,直接输出 -1;二分由于天然映射至有效范围内,故无越界风险。
  • 易错点:如果不知道由于 3 张散牌必能凑成三条而导致所有三条以下的牌型均可以不保存,很容易使得预处理和保存空间爆掉。
  • 数据与验证声明:本题由于没有直接提供官方数据点测试集,目前的逻辑以及对特殊比较位置(例如葫芦里对子的前两张牌的花色优先度等)均与 std.cpp 使用对拍的方式推断验证一致。预留验证给 R3 流程。

验证记录(R2,与官方 std.cpp 三方对拍)

⚠ 本题无本地 data/ ⇒ check_new_analysis 报「无 data/(跳过)」= 空转(T1/T65)。 证据等级 ★★★★(官方 std.cpp 对拍);任何结论一律写成「与官方 std.cpp 三方一致」。

T67 语义核对

项 实测结论 依据
循环结构 cin>>q; while(q--) ⇒ T 显式给出,非多测到 EOF 源码 + 9 个语料 T 与实际输出行数逐点吻合
输入 每询问 6 张:X=前 3(鸡尾酒)、Y=后 3(智乃),全部参与计算 源码
编码 牌 id = (rank-2)*4 + suit(S=1,H=2,C=3,D=4);hash = x*53*53 + y*53 + z 要求 3 张牌按 id 升序 = 题面「点数升、花色降」 差异点 8
输出 5 张牌每张后跟一个空格(★ 行尾有尾随空格)+ \n;输不出则 -1 字节实测
牌型 tp 2..7 = 同花顺/四条/葫芦/同花/顺子/三条;两对/一对/散牌丢弃(无害,见 §结构等价) —
语义 ★ 平局不算赢(cmp2(...) != 1 才输出);答案是最弱的能胜解 V1:v1_tie 与 v1_strongest 均大量失败
★★ 想象牌模型 ★ 可复用对手的牌(非排他) brute.py --exclusive 在 303 组上 fail 2 组,非排他 fail 0 组
★★ 顺子 ★ 无 A-2-3-4-5「轮子」:合法表 73,608 里同花顺只有 36 个、顺子 9180 个(= 9 个窗口,非 10) 与「不能向上越过 A、向下越过 2」一致
复杂度常量 K = 73,608 ✓、索引数 736,080 ✓(≈7.3e5)、峰值 11.9MB ✓ 实测

★ 不看输入也能验的结构等价证据

把 std 的 get2..get7/work 与 main 的 work 放进同一程序, 穷举全部 C(52,5) = 2,598,960 种组合逐组比对:

text
std_valid = 73608    main_valid = 73608
tp_mismatch = 0      f_mismatch = 0
(5 个比较位 f1..f5 ↔ f[0..4] 完全一致)

另测 cmp/cmp2 判定:窗口 300 + 300 万随机对 ⇒ 判定分歧 0; 且 cmp 键 73608 个全不重复(0 冲突) ⇒ ★ 排序是全序,不依赖 std::sort 的 tie 顺序(可移植)。

对拍规模与分歧数(0)

语料 T 构造 vs std
s1b.in 3 官方样例 字节相同
E1 48,400 牌组 2,3,4×4 花色的 C(12,3) 全部有序对 字节相同
E2 48,400 Q,K,A×4 花色全部有序对(覆盖 A 高同花顺) 字节相同
E3 313,600 5–8×4 花色(560 手牌的全有序对,超 T 上限) 字节相同
E4 8,681 ♠2..♠8 单花色(35 手全对)+ 多花色混合 字节相同
R1 100,000 全牌堆均匀随机 6 张 字节相同
R2 60,000 4 点窗口聚簇 字节相同
R3 60,000 对子/三条/四条密集 字节相同
PY.in 17,681 混合 字节相同

合计 639,081 组合成询问 + 官方样例:main.cpp × main.py × std.cpp 三者输出 「字节级」完全一致(0 分歧)。 ★ E1–E4 是穷举不是抽样;§修实现后重跑仍是字节相同。

V6 独立暴力:brute.py 只比较「牌力值元组」 (不复用 main 的排序/索引/二分思路),对 300 组随机全牌堆询问 + 3 组样例: 非排他模型下对 std 与 main 均 0 mismatch (同时反证了上面「非排他」与「最弱解」两条语义)。

V1 全表(失败 行数)

变体 改动 E1 E2 E3 E4 R1 R2 R3 判定
v1_tie 平局算赢 + 二分收等号 48400 48400 313600 8681 96958 60000 59714 承重
v1_strongest 关掉二分(给最强解) 10800 10512 95440 3027 48221 17710 20402 承重
v1_suitflip 花色 tie-break 反向 10560 10272 87456 2316 46020 16263 20384 承重
v1_flushstraight 同花/顺子优先级互换 240 240 3120 844 1938 631 4 承重
★ v1_forder 三条两个单张比较位互换 0 0 0 0 170 0 24 ★ 承重(仅全牌堆随机数据能暴露)
v1_noguard 删 2 个空判防御 0 0 0 0 0 0 0 合法输入下 no-op(如实报告)
v1_keepweak 保留两对/一对/散牌(表 2.6M) 0 0 0 0 0 0 0 no-op(可证)
v1_royal 皇家同花顺独立为第 1 类 0 0 0 0 0 0 0 ★ 结构性等价(不是没覆盖)
v1_tpmax 同花顺整体改名 tp=1 0 0 0 0 0 0 0 no-op(标签是相对的)
v1_forder_strong 把一张三条牌挪进单张位 0 0 0 0 0 0 0 no-op(可证)

★ 探针有效性:v1_tie 在 E1 上 48400/48400 行全错、 v1_strongest 在 R1 上 48221 行错 ⇒ 「0 失败」的变体是真 no-op,不是闸门失灵(T35)。

★★ 本报告最有价值的一条方法学: v1_forder 只在 R1/R3(全牌堆随机)暴露 170/24 行,小牌堆穷举(E1–E4)反而是 0 ⇒ 「小规模穷举」不能替代「全值域随机」 —— 两者是互补的覆盖,不是替代关系。

★★ 「永久性等价」与「数据盲区」的区分(T53 的细化):

  • v1_royal = 0 的理由(非经验主张):皇家同花顺是顺位最高的同花顺, 单独提升为更强的类不改变任何一对牌的比较结果 ⇒ 不可能有数据分辨 ⇒ 这是永久性等价(数学上可证),不是数据盲区
  • v1_keepweak / v1_noguard 的结构理由:任意 3 张不同牌都能补成三条 (取其中一张的点数,补上该点数剩下 3 张中的 2 张)⇒ 最弱能胜解永远 ≥ 三条, 且合法输入下 a[X]/a[Y] 永不为空

V9 UBSan + 对照组 · T38

  • ★ 对照组(INT_MIN 取反)确实报错: runtime error: negation of -2147483648 cannot be represented in type 'int' ⇒ 探针有效

  • -fsanitize=undefined 编译的最终 main.cpp:E1/E3/R1/R2/R3/PY 全部 rc=0, stderr 为空且输出字节仍等于 std ⇒ 无 UB;-ftrapv 版同样 rc=0

  • T38(config.json:1000ms / 128MB):

    程序 语料 耗时 峰值 RSS
    main.cpp(最终) R1(T=100000) 0.05 s 11.9 MB

    ⇒ 耗时余量 20×、内存余量 10.7×