飞飞的赌神修炼手册

飞飞很喜欢打牌,他决定苦练牌技,终成赌神!

飞飞有 A × B 张扑克牌。每张扑克牌有一个大小(整数,记为a,范围区间是 0A - 1)和一个花色(整数,记为b,范围区间是 0B - 1

扑克牌是互异的,也就是独一无二的,也就是说没有两张牌大小和花色都相同。

“一手牌”的意思是你手里有5张不同的牌,这 5 张牌没有谁在前谁在后的顺序之分,它们可以形成一个牌型。 我们定义了 9 种牌型,如下是 9 种牌型的规则,我们用“低序号优先”来匹配牌型,即这“一手牌”从上到下满足的第一个牌型规则就是它的“牌型编号”(一个整数,属于1到9):

  1. 同花顺: 同时满足规则 5 和规则 4.
  2. 炸弹 : 5张牌其中有4张牌的大小相等.
  3. 三带二 : 5张牌其中有3张牌的大小相等,且另外2张牌的大小也相等.
  4. 同花 : 5张牌都是相同花色的.
  5. 顺子 : 5张牌的大小形如 x, x + 1, x + 2, x + 3, x + 4
  6. 三条: 5张牌其中有3张牌的大小相等.
  7. 两对: 5张牌其中有2张牌的大小相等,且另外3张牌中2张牌的大小相等.
  8. 一对: 5张牌其中有2张牌的大小相等.
  9. 要不起: 这手牌不满足上述的牌型中任意一个.

现在, 飞飞从 A × B 张扑克牌中拿走了 2 张牌!分别是 (a1, b1)(a2, b2). (其中a表示大小,b表示花色)

现在要从剩下的扑克牌中再随机拿出 3 张!组成一手牌!!

其实飞飞现在要预言他的未来的可能性,即他将拿到的“一手牌”的可能性,我们用一个 “牌型编号(一个整数,属于1到9)” 来表示这手牌的牌型,那么他的未来有 9 种可能,但每种可能的方案数不一样。

现在飞飞想要计算一下 9 种牌型中,每种牌型的方案数。

Input

1 行包含了整数 AB (1 ≤ A ≤ 25, 1 ≤ B ≤ 4).

2 行包含了整数 a1, b1, a2, b2 (0 ≤ a1, a2 ≤ A - 1, 0 ≤ b1, b2 ≤ B - 1, (a1, b1) ≠ (a2, b2)).

Output

输出一行,这行有 9 个整数,每个整数代表了 9 种牌型的方案数(按牌型编号从小到大的顺序)

限制:设计程序进行枚举,不能使用数学公式推导出每种牌型的方案数式子!

限制:设计程序进行枚举,不能使用数学公式推导出每种牌型的方案数式子!

限制:设计程序进行枚举,不能使用数学公式推导出每种牌型的方案数式子!

测试用例

1

输入

5 2
1 0 3 1

输出

0 0 0 0 8 0 12 36 0 

2

输入

25 4
0 0 24 3

输出

0 2 18 0 0 644 1656 36432 113344 
#include <bits/stdc++.h>
using namespace std;
//卡牌
struct card {
    int dx = 0;  //大小
    int hs = 0;  //花色
    card() {}
    card(const int& d, const int& h) {  //参数分别是大小、花色
        dx = d;
        hs = h;
    }
    bool operator==(const card& c) const {
        return dx == c.dx;  //重载==
    }
    bool operator<(const card& c) const {
        return dx < c.dx;  //重载<
    }
    card operator+(const int& c) const {
        return card(dx + c, hs);  //重载+
    }
};

//分别是每种牌型的方案数
int f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, f6 = 0, f7 = 0, f8 = 0, f9 = 0;
card a[5];        //储存手里的5张牌
vector<card> va;  //储存所有的牌

//判断当前手牌是否为炸弹
bool zadan() {
    if (a[0] == a[1] && a[1] == a[2] && a[2] == a[3])  //前4张大小相同
        return true;
    if (a[1] == a[2] && a[2] == a[3] && a[3] == a[4])  //或者后4张大小相同
        return true;
    return false;
}

//判断当前手牌是否为同花,即5张的花色是否相同
bool tonghua() {
    return a[0].hs == a[1].hs && a[1].hs == a[2].hs && a[2].hs == a[3].hs && a[3].hs == a[4].hs;
}

//判断当前手牌是否为三带二
bool sandaier() {
    if (a[1] == a[2])  //前三张相同、后两张相同
        return a[0] == a[1] && a[3] == a[4];
    if (a[2] == a[3])  //前两张相同、后三张相同
        return a[0] == a[1] && a[3] == a[4];
    return false;
}

//判断当前手牌是否为顺子
bool sunzi() {
    if (a[0] + 1 == a[1])  //大小依次加一
        if (a[1] + 1 == a[2])
            if (a[2] + 1 == a[3])
                if (a[3] + 1 == a[4])
                    return true;
    return false;
}

//判断当前手牌是否为三条
bool santiao() {  // 3种情况:前三张、或者中间三张、或者后面三张相同
    return (a[0] == a[1] && a[1] == a[2]) || (a[1] == a[2] && a[2] == a[3]) || (a[2] == a[3] && a[3] == a[4]);
}
//判断当前手牌是否为两对
bool liangdui() {  // 3种情况:前面一对中间一对、前面一对后面一对、中间一对后面一对
    return (a[0] == a[1] && (a[2] == a[3] || a[3] == a[4])) || (a[1] == a[2] && a[3] == a[4]);
}

//判断当前手牌是否为一对
bool yidui() {
    return a[0] == a[1] || a[1] == a[2] || a[2] == a[3] || a[3] == a[4];
}

//判断当前手牌是否为同花顺
bool tonghuasun() {
    return tonghua() && sunzi();
}

//判断当前手牌的牌型,并且统计该牌型的频率
void pandaun() {  //先手牌按照大小排序,便于判断炸弹、三带二、顺子、同花顺、三条两对、一对
    sort(a, a + 5);
    if (tonghuasun())  //如果是同花顺
        f1++;
    else if (zadan())  //如果是炸弹
        f2++;
    else if (sandaier())  //如果是三带二
        f3++;
    else if (tonghua())  //如果是同花
        f4++;
    else if (sunzi())  //如果是顺子
        f5++;
    else if (santiao())  //如果是三条
        f6++;
    else if (liangdui())  //如果是两对
        f7++;
    else if (yidui())  //如果是一对
        f8++;
    else  //如果是要不起
        f9++;
}

int main() {
    int da, db, ta1, tb1, ta2, tb2;
    cin >> da >> db;                  //整数A和B
    cin >> ta1 >> tb1 >> ta2 >> tb2;  //整数a1、b1、a2、b2
    for (int i = 0; i < da; ++i) {    //创建AXB张牌
        for (int j = 0; j < db; ++j) {//如果这两张牌已经选了就不加入到vector
            if (!((i == ta1 && j == tb1) || (i == ta2 && j == tb2)))
                va.emplace_back(i, j);
        }
    }
    int n = da * db - 2;
    card ka1(ta1, tb1), ka2(ta2, tb2);         //已经选了的两张牌
    for (int i = 0; i < n - 2; ++i)            //从剩下的牌选1张
        for (int j = i + 1; j < n - 1; ++j)    //再从剩下的牌选1张
            for (int k = j + 1; k < n; ++k) {  //再再从剩下的牌选1张
                a[0] = ka1;                    //将当前选择的5张牌放入数组
                a[1] = ka2;
                a[2] = va[i];
                a[3] = va[j];
                a[4] = va[k];
                pandaun();  //判断当前牌型并统计
            }
    cout << f1 << ' ' << f2 << ' ' << f3 << ' ' << f4 << ' ' << f5 << ' ' << f6 << ' ' << f7 << ' ' << f8 << ' ' << f9 << ' ';
    return 0;
}