Vj程序设计复杂模拟题训练

1A : 飞飞的赌神修炼手册

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

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

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

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

  1. 同花顺: 同时满足规则 5 和规则 4.
  2. 炸弹 : 5张牌其中有4张牌的大小相等.
  3. 三带二 : 5张牌其中有3张牌的大小相等,且另外2张牌的大小也相等.
  4. 同花 : 5张牌都是相同花色的.
  5. 顺子 : 5张牌的大小形如 xx + 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 行包含了整数 A 和 B (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;

int main()
{
    int A, B;
    cin >> A >> B;
    int a1, b1, a2, b2;
    cin >> a1 >> b1 >> a2 >> b2;
    int ff[9], f[9];
    for (int i = 0; i < 9; i++)
    {
        f[i] = 0;
        ff[i] = 0;
    }
    vector<pair<int, int>> s(5);
    pair<int, int> m, v;
    m.first = a1;
    v.first = a2;
    m.second = b1;
    v.second = b2;
    s[0] = m;
    s[1] = v;
    // s.push_back(m);
    // s.push_back(v);
    for (int i = 0; i < A; i++)
    {
        for (int j = 0; j < B; j++)
        {
            if (((i != s[0].first) || (j != s[0].second)) && (i != s[1].first || j != s[1].second))
            {
                pair<int, int> s1;
                s1.first = i;
                s1.second = j;
                s[2] = s1;
                for (int ii = 0; ii < A; ii++)
                {
                    for (int jj = 0; jj < B; jj++)
                    {
                        if ((ii != s[0].first || jj != s[0].second) && (ii != s[1].first || jj != s[1].second) && (ii != s[2].first || jj != s[2].second))
                        {
                            pair<int, int> ss;
                            ss.first = ii;
                            ss.second = jj;
                            // s.push_back(ss);
                            s[3] = ss;
                            for (int iii = 0; iii < A; iii++)
                            {
                                for (int jjj = 0; jjj < B; jjj++)
                                {
                                    if ((iii != s[0].first || jjj != s[0].second) && (iii != s[1].first || jjj != s[1].second) && (iii != s[2].first || jjj != s[2].second) && (iii != s[3].first || jjj != s[3].second))
                                    {
                                        pair<int, int> sss;
                                        sss.first = iii;
                                        sss.second = jjj;
                                        // s.push_back(sss);
                                        s[4] = sss;
                                        vector<pair<int, int>> aa(5);
                                        for (int k = 0; k < 5; k++)
                                        {
                                            aa[k] = s[k];
                                        }
                                        sort(aa.begin(), aa.end()); // 排序
                                        int h = 0;                  // 前后相减差1的个数
                                        int hh = 0;                 // 花色相同的个数
                                        int y = 0;                  // 三张牌相同的个数
                                        int yy = 0;                 // 前后数字相同的个数
                                        for (int i = 0; i < 4; i++)
                                        {
                                            if (aa[i].first == aa[i + 1].first - 1)
                                            {
                                                h++;
                                            }
                                            if (aa[i].second == aa[i + 1].second)
                                            {
                                                hh++;
                                            }
                                            if (i <= 2)
                                            {
                                                if (aa[i].first == aa[i + 2].first)
                                                {
                                                    y++;
                                                }
                                            }
                                            if (aa[i].first == aa[i + 1].first)
                                            {
                                                yy++;
                                            }
                                        }
                                        if (h == 4 && hh == 4) //同花顺
                                        {
                                            f[0]++;
                                            ff[0] = 1;
                                        }
                                        else if (y == 2 && yy == 3) // 炸弹
                                        {
                                            f[1]++;
                                            ff[1] = 1;
                                        }
                                        else if (y == 1 && yy == 3) // 三带二
                                        {
                                            f[2]++;
                                            ff[2] = 1;
                                        }
                                        else if (hh == 4 && h != 4) // 相同花色
                                        {
                                            f[3]++;
                                            ff[3] = 1;
                                        }
                                        else if (h == 4 && hh != 4) // 顺子
                                        {
                                            f[4]++;
                                            ff[4] = 1;
                                        }
                                        else if (y == 1) //三张牌相同
                                        {
                                            f[5]++;
                                            ff[5] = 1;
                                        }
                                        else if (yy == 2) // 两对
                                        {
                                            f[6]++;
                                            ff[6] = 1;
                                        }
                                        else if (yy == 1) // 一对
                                        {
                                            ff[7] = 1;
                                            f[7]++;
                                        }
                                        else
                                        {
                                            f[8]++;
                                        }
                                        // s.pop_back();
                                    }
                                }
                            }
                            // s.pop_back();
                        }
                    }
                }
                // s.pop_back();
            }
        }
    }
    for (int i = 0; i < 9; i++)
    {
        cout << f[i] / 6 << " ";
    }
    cout << endl;
    
    return 0;
}

2B : TT与可怜的猫

题目描述

自从 TT 成为了助教,他就热衷于给同学们解答疑问,于是他就没有时间进行陪他的猫猫玩了,真是一只可怜的小猫。

TT 在同一时间会与很多同学同时用 QQ(TT 特供版) 进行答疑,有时 TT 开启一个新的窗口,开始一个新的答疑对话;有时 TT 关闭一个窗口,结束一段答疑; 有时,为了及时回答着急的同学,TT 会把一个对话窗口设置为置顶状态(置顶状态是一种虚拟的状态,窗口的实际位置并不会发生改变)。

你可以将 TT 的聊天窗口想象成一个队列。如果现在没有窗口处于置顶状态,那么在队列中位列第一窗口视为在顶层,否则处于置顶状态的窗口视为在顶层。请注意,不可能同时存在两个窗口处于置顶状态(也就是说,处于置顶状态的窗口,要么不存在,要么只有一个)。如果当前置顶的窗口被关闭了,则剩余队列中第一窗口视为在顶层

TT 为了安抚自己的猫,于是给猫猫看自己的聊天记录解闷,根据猫猫看屏幕中窗口的时间,TT 给每个窗口分配了一个喜爱度,TT 认为喜爱度越高,猫猫越开心。由于猫猫具有不确定的生物特性,所以所有的喜爱度都是不同的。

作为 TT 特供版 QQ 的研发人员,你要负责完成的工作是为软件记录 TT 的操作,形成一个日志系统。日志有固定的记录格式:OpId #X: MSG. ,其中 X 是操作的编号,而 MSG 是日志的提示信息,需要使用特定的字符串进行替换。

TT 可能会用到的操作如下:

  1. Add u: TT 打开一个喜爱度为 u 的新窗口,若 u 不与当前窗口队列中的某个窗口重复,则该新窗口将新建成功,并成为窗口队列中的最后一个窗口。 如果创建成功,则 MSG 记录 success。 否则, MSG 记录 same likeness

  2. Close u: TT 关掉了一个喜爱度为 u 的窗口,如果该窗口存在,则将其关闭,MSG 记录 close u with c,u 表示喜爱度,c 表示该窗口上次打开至今交流的话的数量。若该窗口不存在,则 MSG 记录 invalid likeness

  3. Chat w: TT 和顶层窗口交流了 w 句话,如果当前队列中没有窗口,则 MSG 记录 empty,否则记录 success

  4. Rotate x: 将队列中第 x 个窗口放在队首,若 x 大于当前队列中窗口数或小于 1 ,则 MSG 记录 out of range,否则记录 success。举个例子,目前队列中有喜爱度为 5,3,2,8 的四个窗口,Rotate 3 之后,会将喜爱度为 2 的第 3 个窗口放在首位,结果为 2,5,3,8。

  5. Prior: TT 将目前喜爱度最大的窗口放在队首,如果当前队列中没有窗口,则 MSG 记录 empty,否则记录 success

  6. Choose u: TT 将喜爱度为 u 的窗口放在队首,如果喜爱度为 u 的窗口存在,则 MSG 记录 success,否则记录 invalid likeness

  7. Top u: TT 将喜爱度为 u 的窗口设定为置顶状态,如果喜爱度为 u 的窗口存在,则 MSG 记录 success,否则记录 invalid likeness。注意,处于置顶状态的窗口最多不超过一个,也就是说,如果在此次设定前已经有处于置顶状态的窗口,则原有置顶状态的窗口的置顶状态将会消失。(置顶只是一种虚拟的状态,原窗口在队列中的位置不会发生变化)

  8. Untop: TT 取消当前处于置顶状态窗口的置顶状态。如果当前没有窗口处于置顶状态,则 MSG 记录 no such person,否则记录 success

最后,由于 TT 要给自己的猫猫树立一个讲文明有礼貌的榜样,所以在上述操作完成后,还要进行若干次操作,这些操作是:与当前队列中所有说过话的窗口说拜拜。MSG 记录 Bye u: c, u 表示喜爱度,c 表示该窗口上次打开至今交流的话的数量。即:TT 先和位于顶层的窗口说拜拜,然后将其关闭,如果 TT 没有和当前顶层窗口说过话,则直接将其关闭,如此操作下去,直到队列为空。

输入描述

第一行包含一个整数 T(T≤5),表示数据组数。

对于每组数据,第一行一个 n,表示执行的操作数,其中 0<n≤5000。接下来 n 行,每行输入一个操作,保证所有输入数据中的整数不大于 109。

输出描述

对于每个指定的操作,按照日志的格式,每个操作行。对于最后的非指定操作,同样按照日志的格式,每个操作一行。

测试样例

样例 1

输入:

1
30
Add 4
Add 3
Chat 4
Add 3
Rotate 2
Chat 5
Prior
Top 3
Choose 4
Rotate 1
Add 2
Close 4
Chat 7
Choose 2
Chat 7
Add 3
Top 2
Add 4
Choose 3
Chat 7
Prior
Top 3
Rotate 1
Rotate 3
Chat 7
Top 4
Add 2
Close 2
Prior
Add 4

输出:

OpId #1: success.
OpId #2: success.
OpId #3: success.
OpId #4: same likeness.
OpId #5: success.
OpId #6: success.
OpId #7: success.
OpId #8: success.
OpId #9: success.
OpId #10: success.
OpId #11: success.
OpId #12: close 4 with 4.
OpId #13: success.
OpId #14: success.
OpId #15: success.
OpId #16: same likeness.
OpId #17: success.
OpId #18: success.
OpId #19: success.
OpId #20: success.
OpId #21: success.
OpId #22: success.
OpId #23: success.
OpId #24: success.
OpId #25: success.
OpId #26: success.
OpId #27: same likeness.
OpId #28: close 2 with 7.
OpId #29: success.
OpId #30: same likeness.
OpId #31: Bye 3: 26.

解答

#include <bits/stdc++.h>

using namespace std;
// #define inf 1e6
long long T;
long long n;
long long tot;

struct Window
{
    long long x, y; // y为说话量,x为喜欢程度,z为是否打开
    /* data */
} w[1000000];
long long top; // 置顶的窗口的序号
string a;
long long b;
// pair<long long, long long> C[1000000]; // first为喜爱度,second为是否打开
// 初始化
void init()
{
    for (long long i = 0; i < 1000000; i++)
    {
        // C[i].first = -1;
        // C[i].second = 0;
        w[i].x = -1;
        w[i].y = 0;
        // w[i].z = 0;
        // w[i].k = 0;
    }
    // w[1]. = 1;
    tot = 1;
}
long long j;
void play(long long i);

void bye();
int main()
{
    // freopen("1.txt", "r", stdin);
    // freopen("2.txt", "w", stdout);
    cin >> T;

    for (long long i = 1; i <= T; i++)
    {
        cin >> n;
        init();
        top = -1;
        for (j = 1; j <= n; j++)
        {
            cin >> a;
            play(j);
        }
        bye();
    }
    // system("pause");
    return 0;
}

void bye()
{
    if (top != -1)
    {
        if (w[top].y != 0)
        {
            // j++;
            cout << "OpId #" << j << ": ";
            cout << "Bye " << w[top].x << ": " << w[top].y << "." << endl;
            j++;
        }
        // }
        for (long long i = 1; i < tot; i++)
        {
            if (w[i].x == w[top].x || w[i].y == 0)
            {
                continue;
            }
            else
            {
                // j++;
                cout << "OpId #" << j << ": ";
                cout << "Bye " << w[i].x << ": " << w[i].y << "." << endl;
                j++;
            }
        }
    }
    else
    {
        for (long long i = 1; i < tot; i++)
        {
            if (w[i].y != 0)
            {
                cout << "OpId #" << j << ": ";
                cout << "Bye " << w[i].x << ": " << w[i].y << "." << endl;
                j++;
            }
        }
    }
}

void play(long long i)
{
    // switch (a)
    // {
    if (a == "Add")
    {
        cin >> b;
        long long g = 1;
        for (; g < tot; g++)
        {
            if (w[g].x == b)
            {
                break;
            }
        }
        // long long d = 1;
        // for (; d < tot; d++)
        // {
        //     if (C[d].first == b)
        //     {
        //         break;
        //     }
        // }
        if (g >= tot)
        {
            w[tot].x = b;
            // C[tot] = 1;
            tot++;

            cout << "OpId #" << i << ": success." << endl;
        }
        // else if (C[d].second == 0)
        // {
        // cout << "OpId #" << i << ": success." << endl;
        // }
        else
        {
            cout << "OpId #" << i << ": same likeness." << endl;
        }
        // C[tot - 1] = 1;
        // C[tot - 1].first = b;
        // C[tot - 1].second = 1;
        // break;
    }
    else if (a == "Close")
    {
        cin >> b;
        long long g = 1;
        for (; g < tot; g++)
        {
            if (w[g].x == b)
            {
                break;
            }
        }
        if (g >= tot)
        {
            cout << "OpId #" << i << ": invalid likeness." << endl;
        }
        else
        {
            if (top > g && top != -1)
            {
                top--;
            }
            else if (top == g)
            {
                top = -1;
            }
            cout << "OpId #" << i << ": close " << b << " with " << w[g].y << "." << endl;
            for (int h = g; h < tot - 1; h++)
            {
                w[h].x = w[h + 1].x, w[h].y = w[h + 1].y;
            }
            w[tot - 1].x = -1, w[tot - 1].y = 0;
            tot--;
            // long long d = 1;
            // for (; d < tot; d++)
            // {
            //     if (C[d].first == b)
            //     {
            //         break;
            //     }
            // }
            // if (C[d].second != 0)
            // {
            // C[d].second = 0;
            // w[g].z = 0;

            // w[g].y = 0;
            // }
            // else
            // {
            //     cout << "OpId #" << i << ": invalid likeness." << endl;
            // }
        }
        // break;
    }
    else if (a == "Chat")
    // case "Chat":
    {
        cin >> b;
        if (tot == 1)
        {
            cout << "OpId #" << i << ": empty." << endl;
        }
        else
        {
            if (top == -1)
            {
                w[1].y = b + w[1].y;
                // C[1].second = 1;
                cout << "OpId #" << i << ": success." << endl;
            }
            else
            {
                // if (C[top].second == 0)
                // {
                //     w[1].y = b;
                //     C[1] = 1;
                cout << "OpId #" << i << ": success." << endl;
                // }
                // else
                // {
                w[top].y = b + w[top].y;
                // C[top] = 1;
                // }
            }
        }
    }
    else if (a == "Rotate")
    // case "Rotate":
    {
        cin >> b;
        if (b >= tot || b < 1)
        {
            cout << "OpId #" << i << ": out of range." << endl;
        }
        else
        {
            if (top < b && top != -1)
            {
                top++;
            }
            else if (top == b)
            {
                top = 1;
            }
            long long x1, y1, z1;
            x1 = w[b].x, y1 = w[b].y;
            for (long long g = b; g > 1; g--)
            {
                w[g].x = w[g - 1].x;
                w[g].y = w[g - 1].y;
                // w[g].z = w[g - 1].z;
            }
            w[1].x = x1, w[1].y = y1;
            cout << "OpId #" << i << ": success." << endl;
        }
        // break;
    }
    else if (a == "Prior")
    // case "Prior":
    {
        if (tot == 1)
        {
            cout << "OpId #" << i << ": empty." << endl;
        }
        else
        {
            cout << "OpId #" << i << ": success." << endl;
            long long f = 1;
            long long u = w[1].x;
            for (long long g = 1; g < tot; g++)
            {
                if (w[g].x > u)
                {
                    u = w[g].x;
                    f = g;
                }
            }
            if (top < f && top != -1)
            {
                top++;
            }
            else if (top == f)
            {
                top = 1;
            }
            long long x1, y1, z1;
            x1 = w[f].x, y1 = w[f].y;
            for (long long g = f; g > 1; g--)
            {
                w[g].x = w[g - 1].x;
                w[g].y = w[g - 1].y;
                // w[g].z = w[g - 1].z;
            }
            w[1].x = x1, w[1].y = y1;
        }
        // break;
    }
    else if (a == "Choose")
    // case "Choose":
    {
        cin >> b;
        long long g = 1, f = -1;
        for (; g < tot; g++)
        {
            if (w[g].x == b)
            {
                f = g;
                break;
            }
        }
        if (f < tot && f != -1)
        {
            long long x1, y1, z1;
            if (top < f && top != -1)
            {
                top++;
            }
            else if (top == f)
            {
                top = 1;
            }
            x1 = w[f].x, y1 = w[f].y;
            for (long long h = f; h > 1; h--)
            {
                w[h].x = w[h - 1].x;
                w[h].y = w[h - 1].y;
            }
            w[1].x = x1, w[1].y = y1;
            cout << "OpId #" << i << ": success." << endl;
        }
        else
        {
            cout << "OpId #" << i << ": invalid likeness." << endl;
        }
        // break;
    }
    else if (a == "Top")
    // case "Top":
    {
        cin >> b;
        long long g = 1, f = -1;
        for (; g < tot; g++)
        {
            if (w[g].x == b)
            {
                f = g;
                break;
            }
        }
        if (f < tot && f != -1)
        {
            top = f;
            cout << "OpId #" << i << ": success." << endl;
        }
        else
        {
            cout << "OpId #" << i << ": invalid likeness." << endl;
        }
        // break;
    }
    else if (a == "Untop")
    // case "Untop":
    {
        // long long g = 1;
        // for (; g < tot; g++)
        // {
        //     // if (w[g].k == 2)
        //     // {
        //     //     break;
        //     // }
        // }
        if (top != -1)
        {
            top = -1;
            cout << "OpId #" << i << ": success." << endl;
        }
        else
        {
            cout << "OpId #" << i << ": no such person." << endl;
        }
        // break;
    }
    // }
}

3C : 记事本

注:本题有较多的部分分,请参看数据规模部分。

题目描述

记事本是 Windows 平台下一款经典的文本编辑器,其存储文件的扩展名为 .txt,文件属性没有任何格式标签或者风格,所以相当适合在 DOS 环境中编辑。

在本题中,可能会用到的按键如下图所示:

光标移动

光标表示当前要进行输入等操作的位置,在本题中,我们假设所有字符都是等宽的。

光标的位置可以用行列坐标来描述,光标所在的行和列均从 1 开始,例如:

以下操作可以进行光标的移动,使用 MOVE <comd> 输入相关的操作,其中 <comd> 表示指令,可以使用以下字符串代替:

  • Home:把光标移动到当前行的开头。
  • End:把光标移动到当前行的末尾。
  • Up:光标移动到上一行的相同列。
    • 若当前为第一行,则不进行任何操作。
    • 若上一行的列数小于当前光标的列数,则将光标移动到上一行的末尾。
  • Down:光标移动到下一行的相同列。
    • 若当前为最后一行,则不进行任何操作。
    • 若下一行的列数小于当前光标的列数,则将光标移动到下一行的末尾。
  • Left:光标左移一位。
    • 若当前光标位于记事本开始,则不进行任何操作。
    • 若当前光标处于某一行的开头,则将光标移动到上一行的末尾。
  • Right:光标右移一位。
    • 若当前光标位于记事本末尾,则不进行任何操作。
    • 若当前光标处于某一行的末尾,则将光标移动到下一行的开头。

输入

以下操作可以在光标后进行输入,使用 INSERT <comd> 输入相关的操作,其中 <comd> 表示指令,可以使用以下字符串代替:

  • Char <char>:输入一个字符,其中 <char> 是输入的字符。

    • <char> 可能是一下字符中的任意一个:

    注:下列字符中不包含空格与换行符

    `1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?
    
    • 例如:INSERT Char a 表示在当前光标后插入 a 字符。
  • Enter:输入换行符,并进行换行。

  • Space:输入空格。

  • Paste:在当前光标后,插入粘贴板中的内容,若粘贴板中无内容,则忽略当前操作。

删除

以下操作可以删除记事本中的内容,使用 REMOVE <comd> 输入相关的操作,其中 <comd> 表示指令,可以使用以下字符串代替:

  • Del:删除当前光标位置之后的一个字符。
    • 若该字符为换行符,则当前行与下一行合并为一行。
    • 若当前光标在文件末尾,则忽略当前操作。
  • Backspace:删除当前光标位置之前的一个字符。
    • 若该字符为换行符,则当前行与上一行合并为一行。
    • 若当前光标在文件开头,则忽略当前操作。

粘滞功能(分数占比 24 分)

输入 SHIFT 指令,可以启动或关闭粘滞功能。

  • 开始时粘滞功能默认为关闭状态,之后每次点击:

    • 若当前为启动状态,则关闭;
    • 若当前为关闭状态,则启动。
  • 粘滞功能启动时,记录当前的光标位置为 记录点

  • 粘滞功能关闭时,若此时的光标位置与 记录点 的位置不同,则进入选中状态

  • 粘滞功能启动后,直到功能关闭前,不会对记事本进行除光标移动外的任何操作

当进入选中状态后,通过记录点与当前光标,可以唯一的确定一段内容,现令记录点与光标之间的所有字符(包括换行符)为 选中字段

例如,记录点位于第 1 行第 2 列,光标位于第 2 行第 4 列时,选中字段如下图所示:

当前 处于选中状态 时,对于不同的情况,需要按照序号依次执行以下操作:

  • 若进行光标移动

    1. 退出选中状态
    2. 尝试进行光标的移动(无论光标最终是否移动,都会退出选中状态)。
  • 若进行输入

    1. 将选中内容替换为输入内容;
    2. 退出选中状态
  • 若进行删除

    1. 删除当前选中内容;
    2. 退出选中状态
  • 若再次启动粘滞功能退出选中状态,但保留上一次选中字段的 记录点 作为当前记录点

  • 若进行查找,字数统计,复制,打印操作,则在操作后仍然保持选中状态

查找

输入 FIND <word> 指令,进行字符串查找,其中 <word> 为输入的要查找的字符串,该字符串中不包含空格与换行符。

执行该指令时,要根据当前是否处于选中状态做不同的处理:

  • 若当前处于选中状态:查找输入字符串在选中字段中的出现次数并输出。
  • 否则:查找输入字符串在当前记事本中的出现次数并输出。

例如:当前没有选中的内容,且记事本中的内容为 ababa,若执行 FIND aba,则应当输出 2,分别在第 1 列与第 3 列出现过。

字数统计

输入 COUNT 指令,进行字数统计。

执行该指令时,要根据当前是否处于选中状态做不同的处理:

  • 若当前处于选中状态:输出当前选中字段中的可见字符(不包括空格与换行符)的数量。
  • 否则:输出当前文档中可见字符(不包括空格与换行符)的数量。

复制

输入 COPY 指令,进行复制操作。

执行该指令时,要根据当前是否处于选中状态做不同的处理:

  • 若当前处于选中状态:复制选中字段到粘贴板;
  • 否则,
    • 若当前行不为空:复制当前行的内容(不包括换行符)到粘贴板;
    • 否则:忽略当前操作。

打印

输入 PRINT 指令,输出当前的记事本中的全部内容,并在之后输出一个换行符。

输入格式

输入包含 n+1 行。
第一行包含一个整数 n,表示接下来指令的数量。
接下来 n 行,每行一条指令,格式形如题目描述中的叙述。

输出格式

对于需要输出的指令,进行相应的输出。
若为 FIND 与 COUNT 操作,输出一行表示相应的数字。
若为 PRINT 操作,则输出若干行,表示记事本的当前内容,并在之后输出一个换行。

请注意:所有的输出不要有多余的空格。

测试样例

样例输入

20
INSERT Char #
INSERT Enter
INSERT Char C
INSERT Enter
INSERT Space
INSERT Char _
INSERT Char _
PRINT
INSERT Char >
INSERT Enter
INSERT Char h
INSERT Char h
INSERT Char h
INSERT Enter
PRINT
COUNT
FIND __
REMOVE Del
REMOVE Backspace
PRINT

样例输出

#
C
 __
#
C
 __>
hhh

8
1
#
C
 __>
hhh

数据规模

对于 100% 的测试数据,1≤n≤5000。

不同测试点所包含的功能不同,其具体情况如下表所示。

解答

#include <bits/stdc++.h>
using namespace std;
const string NULLSTR = "null";
const string ENTER = "\n";
const string SPACE = " ";
vector<string> line;     //lines of the file
vector<string> pasteBin; //lines of pasteBin
vector<string> selBin;   //lines of selection
struct pos
{
    int row = 1, col = 1;
    bool operator<(const pos &pp) const
    {
        if (row == pp.row)
            return col < pp.col;
        return row < pp.row;
    }
    bool operator==(const pos &pp) const
    {
        return (row == pp.row) && (col == pp.col);
    }
    pos(int r, int c) : row(r), col(c) {}
    pos() { row = col = 1; }
};
pos Cursor;      //position of the Cursor 0=row,1=column,element=1,2,...
bool shifted = false;     //shift enabled or not.
bool inSelection = false; //selection mode enabled or not.
pos remPoint;             //remPoint for selection. (Just a copy of the Cursor there.)
pos selection[2];         //selection area.
int getSpeciLineIndex(const pos &p) { return p.row - 1; }
int getSpeciCharIndex(const pos &p) { return p.col - 2; }
int getSpeciLineFullLength(const pos &p) { return line[getSpeciLineIndex(p)].length(); } //get the string length of current line.
int getSpeciLineVisLength(const pos &p)
{
    if (*(line[getSpeciLineIndex(p)].rbegin()) == '\n')
        return line[getSpeciLineIndex(p)].length() - 1;
    return getSpeciLineFullLength(p);
}
string getSpeciCursorLeftSub(const pos &p) { return line[getSpeciLineIndex(p)].substr(0, p.col - 1); } //get the substring on the left of the Cursor of the line.
string getSpeciCursorRightSub(const pos &p) { return line[getSpeciLineIndex(p)].substr(p.col - 1); }   //get the substring on the right of the Cursor of the line.
string getSpeciLineVisStr(const pos &p) { return line[getSpeciLineIndex(p)].substr(0, getSpeciLineVisLength(p)); }
void theCopy(vector<string> &);
vector<string> getSelectionArea()
{ //return the range of selection. if not in selection, then  return the whole file.
    vector<string> range;
    if (inSelection)
    {
        //        pasteBinBackUp=pasteBin;
        theCopy(selBin);
        range = selBin;
        //        pasteBin=pasteBinBackUp;
    }
    else
        range = line;
    return range;
}
void Move(int type)
{
    inSelection = false;
    bool moveLR = false;
    if(type == 1){
        Cursor.col = 1;
    }else if(type == 2){
        Cursor.col = getSpeciLineVisLength(Cursor) + 1;
    }else if(type==3){
        if (Cursor.row == 1)
                return;
            moveLR = false;
            if (getSpeciLineVisLength(pos(Cursor.row - 1, Cursor.col)) < Cursor.col - 1)
                moveLR = true; //moded getCurLineLength().
            --Cursor.row;
            if (moveLR)
                Move(2);
    }else if(type ==4){
        if (Cursor.row == line.size())
                return;
            moveLR = false;
            if (getSpeciLineVisLength(pos(Cursor.row + 1, Cursor.col)) < Cursor.col - 1)
                moveLR = true; //moded getCurLineLength().
            ++Cursor.row;
            if (moveLR)
                Move(2);
    }else if(type==5){
        if (Cursor.row == 1 && Cursor.col == 1)
                return;
            if (Cursor.col == 1)
            {
                Move(3);
                Move(2);
                return;
            }
            --Cursor.col;
    }else if(type ==6){
        if (Cursor.row == line.size() && Cursor.col == getSpeciLineVisLength(Cursor) + 1)
                return;
            if (Cursor.col == getSpeciLineVisLength(Cursor) + 1)
            { //moded getCurLineLength().
                Move(4);
                Move(1);
                return;
            }
            ++Cursor.col;
    }else if(type ==7){
        Cursor.col = getSpeciLineVisLength(Cursor) + 2; //moded getCurLineLength().
    }

    
}

void insert(int, string arg);
void createNextLineWithStr(string str)
{
    auto ins = line.begin();
    for (int i = 1; i <= getSpeciLineIndex(Cursor); i++)
        ++ins;
    line.insert(++ins, str);
    Move(4);
    Move(2);
}

void theCopy(vector<string> &bin)
{
    if (inSelection)
    {
        bin.clear();
        if (selection[0].row == selection[1].row)
        {
            int leftIndex = getSpeciCharIndex(selection[0]) + 1;
            int rightIndex = getSpeciCharIndex(selection[1]);
            if (leftIndex >= 0 && rightIndex >= 0)
                bin.push_back(line[getSpeciLineIndex(selection[1])].substr(leftIndex, rightIndex - leftIndex + 1));
        }
        else
        {
            int upCharIndex = getSpeciCharIndex(selection[0]) + 1;
            int upLineIndex = getSpeciLineIndex(selection[0]);
            int dnCharIndex = getSpeciCharIndex(selection[1]);
            int dnLineIndex = getSpeciLineIndex(selection[1]);
            if (upCharIndex >= 0)
                bin.push_back(line[upLineIndex].substr(upCharIndex));
            else
                bin.push_back(line[upLineIndex]);
            for (int i = upLineIndex + 1; i < dnLineIndex; i++)
            {
                string tmp = line[i];
                bin.push_back(tmp);
            }
            if (dnCharIndex >= 0)
                bin.push_back(line[dnLineIndex].substr(0, dnCharIndex + 1));
        }
        return;
    }
    else if (getSpeciLineVisLength(Cursor) != 0)
    {
        bin.clear();
        bin.push_back(getSpeciLineVisStr(Cursor));
        return;
    }
}

void theRemove(int);
void insert(int type, string arg)
{
    vector<string>::iterator ins;
    string left, right;
    if (inSelection)
    {
        if (type == 4 && pasteBin.empty())
            return;
        if (selection[1] == selection[0])
        {
            Cursor = selection[1];
            inSelection = false;
            insert(type, arg);
            return;
        }
        theRemove(1); //type can be any value.
        insert(type, arg);
        inSelection = false;
        return;
    }
    switch (type)
    {
        case 1:
            line[getSpeciLineIndex(Cursor)] = getSpeciCursorLeftSub(Cursor) + arg + getSpeciCursorRightSub(Cursor);
            Cursor.col += arg.length();
            break;
        case 2:
            right = getSpeciCursorRightSub(Cursor);
            line[getSpeciLineIndex(Cursor)] = getSpeciCursorLeftSub(Cursor) + ENTER;
            ins = line.begin();
            for (int i = 1; i <= getSpeciLineIndex(Cursor); i++)
                ++ins;
            line.insert(++ins, right);
            Move(4);
            Move(1);
            break;
        case 3:
            line[getSpeciLineIndex(Cursor)] = getSpeciCursorLeftSub(Cursor) + SPACE + getSpeciCursorRightSub(Cursor);
            ++Cursor.col;
            break;
        case 4:
            if (pasteBin.empty())
                return;
            right = getSpeciCursorRightSub(Cursor);
            if (pasteBin.size() == 1 && *(pasteBin[0].rbegin()) != '\n')
            {
                line[getSpeciLineIndex(Cursor)] = getSpeciCursorLeftSub(Cursor) + pasteBin[0] + right;
                for (int i = 0; i < pasteBin[0].size(); i++)
                    Move(6);
            }
            else
            {
                int curLine = -1;
                line[getSpeciLineIndex(Cursor)] = getSpeciCursorLeftSub(Cursor) + pasteBin[++curLine];
                for (int i = 1; i < pasteBin.size() - 1; i++)
                    createNextLineWithStr(pasteBin[++curLine]);
                if (*(pasteBin[pasteBin.size() - 1].rbegin()) != '\n')
                {
                    if (curLine + 1 <= pasteBin.size() - 1)
                        createNextLineWithStr(pasteBin[pasteBin.size() - 1] + right);
                    Move(1);
                    for (int i = 0; i < pasteBin[pasteBin.size() - 1].size(); i++)
                        Move(6);
                }
                else
                {
                    if (curLine + 1 <= pasteBin.size() - 1)
                        createNextLineWithStr(pasteBin[pasteBin.size() - 1]);
                    createNextLineWithStr(right);
                    Move(1);
                }
            }
            break;
    }
}

void theRemove(int type)
{
    vector<string>::iterator ins;
    string left, right;
    if (inSelection)
    {
        theCopy(selBin);
        left = getSpeciCursorLeftSub(selection[0]);
        right = getSpeciCursorRightSub(selection[1]);
        Cursor = selection[0];
        line[getSpeciLineIndex(selection[0])] = left + right;
        int firstDelLineIndex;
        firstDelLineIndex = getSpeciLineIndex(selection[0]) + 1;
        for (int i = firstDelLineIndex; i <= selection[1].row - 1;)
        {
            ins = line.begin();
            for (int j = 1; j <= i; j++)
                ++ins;
            line.erase(ins);
            --selection[1].row;
        }
        inSelection = false;
        if (Cursor.row > line.size())
        {
            Move(3);
            Move(2);
        }
        return;
    }
    switch (type)
    {
        case 1:
            if (getSpeciLineIndex(Cursor) + 1 == line.size() && getSpeciCharIndex(Cursor) == getSpeciLineVisLength(Cursor) - 1)
                return; //moded getCurLineLength().
            if (getSpeciCharIndex(Cursor) == getSpeciLineVisLength(Cursor) - 1)
            { //moded getCurLineLength().
                line[getSpeciLineIndex(Cursor)] = getSpeciLineVisStr(Cursor) + line[getSpeciLineIndex(Cursor) + 1];
                ins = line.begin();
                for (int i = 1; i <= getSpeciLineIndex(Cursor); i++)
                    ++ins;
                line.erase(++ins);
                return;
            }
            left = getSpeciCursorLeftSub(Cursor);
            right = getSpeciCursorRightSub(Cursor).substr(1);
            line[getSpeciLineIndex(Cursor)] = left + right;
            break;
        case 2:
            if (getSpeciCharIndex(Cursor) == -1 && getSpeciLineIndex(Cursor) == 0)
                return;
            if (getSpeciCharIndex(Cursor) == -1)
            {
                pos tmpCurs = Cursor; //backup the Cursor. so we can move the Cursor before line is merged.
                Move(3);
                Move(2);
                line[getSpeciLineIndex(tmpCurs) - 1] = getSpeciLineVisStr(pos(tmpCurs.row - 1, tmpCurs.col)) + line[getSpeciLineIndex(tmpCurs)];
                ins = line.begin();
                for (int i = 1; i <= getSpeciLineIndex(tmpCurs); i++)
                    ++ins;
                line.erase(ins);
                return;
            }
            left = getSpeciCursorLeftSub(Cursor).substr(0, getSpeciCharIndex(Cursor));
            right = getSpeciCursorRightSub(Cursor);
            line[getSpeciLineIndex(Cursor)] = left + right;
            --Cursor.col; //Cursor goes back 1 char.
            break;
    }
}

int theFind(string word)
{
    vector<string> range = getSelectionArea();
    int ans = 0;
    for (string curLine : range)
    {
        int fIndex = 0;
        while (fIndex < curLine.length() && (fIndex = curLine.find(word)) != string::npos)
        {
            ++ans;
            curLine = curLine.substr(fIndex + 1);
            fIndex = 0;
        }
    }
    return ans;
}

void shift()
{
    shifted = !shifted;
    if (shifted)
    {
        if (inSelection)
        {
            inSelection = false;
            return;
        }
        remPoint = Cursor;
    }
    else
    {
        if (remPoint == Cursor)
            return;
        if (remPoint < Cursor)
        {
            selection[0] = remPoint;
            selection[1] = Cursor;
        }
        else
        {
            selection[1] = remPoint;
            selection[0] = Cursor;
        }
        inSelection = true;
    }
}

int theCount()
{
    vector<string> range = getSelectionArea();
    int ans = 0;
    for (string str : range)
        for (char c : str)
            if (c != ' ' && c != '\n')
                ans++;
    return ans;
}

void thePrint()
{
    for (string str : line)
        if (!str.empty())
            cout << str;
    cout << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    int opCnt;
    cin >> opCnt;
    line.emplace_back("");
    string op, arg1;
    bool insertChar = false; //for debug.
    for (int opI = 1; opI <= opCnt; opI++)
    {
        insertChar = false;
        cin >> op;
        switch(op[0]){
            case 'M': {
                cin >> arg1;
                switch(arg1[0]){
                    case 'H':{
                        Move(1);
                        break;
                    }
                    case 'E':{
                        Move(2);
                        break;
                    }
                    case 'U':{
                        Move(3);
                        break;
                    }
                    case 'D':{
                        Move(4);
                        break;
                    } 
                    case 'L':{
                        Move(5);
                        break;
                    }
                    case 'R':{
                        Move(6);
                        break;
                    }
                }
         
            break;
            }
            case 'I':
                    {
                        cin >> arg1;
                        switch(arg1[0]){
                            case 'C':{
                                string arg2;
                            cin >> arg2;
                            insert(1, arg2);
                            insertChar = true; // for debug.
                            break;
                            }
                            case 'E':{
                                insert(2, NULLSTR);
                                break;
                            }
                            case 'S':{
                                insert(3, NULLSTR);
                                break;
                            }
                            case 'P':{
                                insert(4, NULLSTR);
                                break;
                            }
                        }
                  
                        break;
                    }
            case 'R': {
                cin >> arg1;
            if (arg1 == "Del")
            {
                theRemove(1);
            }
            else if (arg1 == "Backspace")
            {
                theRemove(2);
            }
            break;
            }
            case 'S':{
                shift();
                break;
            }
            case 'F':{
                cin >> arg1;
            int ans = theFind(arg1);
            cout << ans << endl;
            break;
            }
            case 'C':{
                if(op[2]=='P'){
                    theCopy(pasteBin);
                }else if(op[2]=='U'){
                    cout << theCount() << endl;
                }
                break;
            }
            case 'P':{
                thePrint();
                break;
            }
        }
        
    }
    return 0;
}

4D : 猪国杀(模板)

请使用指定的代码模板完成该题~

  • 由于原题在题面和数据上的一些小问题,本题经过了一些小修小改,数据,和题面,与 SDOI2010 略有不同。参考网络资料将让你在完成作业的路径上绕远路(不保证可行)并且收获甚少。相信自己,独立完成会收获很多,你也可以在思考无所获后向同学请教。
  • 代码模板精心制作,请大家理解后进行补全代码实验
    • 本题代码模板不严格遵守面向对象的规则,而是面向教育用途设计
    • 比起费力优化代码的常数复杂度,更乐于精心设计将代码逻辑区分开
  • 本实验考点:
    • 问题理解及其逻辑化能力
    • 大型(显然并不大 第三方代码框架理解和分析能力
    • 工程改动的创口分析和实践能力
    • 程序调试能力
  • 期末将近,预祝同学们期末考得好成绩,不负努力,加油。

背景

《猪国杀》是一种多猪牌类回合制游戏,一共有 3 种角色:主猪,忠猪,反猪。每局游戏主猪有且只有 1 只,忠猪和反猪可以有多只,每只猪扮演 1 种角色。

目的

主猪 / MP:自己存活的情况下消灭所有的反猪。
忠猪 / ZP:不惜一切保护主猪,胜利条件与主猪相同。
反猪 / FP:杀死主猪。

游戏过程

游戏开始时,每个玩家手里都会有 4 张牌,且体力上限和初始体力都是 4 。

开始游戏时,从主猪开始,按照逆时针方向(数据中就是按照编号从 1,2,3…n 的顺序)依次行动。

每个玩家自己的回合可以分为 2 个阶段:

  • 摸牌阶段:从牌堆顶部摸 2 张牌,依次放到手牌的最右边;
  • 出牌阶段:你可以使用任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。当然,要满足如下规则:
  1. 如果没有猪哥连弩,每个出牌阶段只能使用 1 次「杀」来攻击;
  2. 任何牌被使用后被弃置(武器是装备上);被弃置的牌以后都不能再用,即与游戏无关。

各种牌介绍

每张手牌用 1 个字母表示,字母代表牌的种类。

基本牌

『桃 / P』在自己的回合内,如果自己的体力值不等于体力上限,那么使用 1 个桃可以为自己补充 1 点体力,否则不能使用桃;桃只能对自己使用;在自己的回合外,如果自己的血变为 0 或者更低,那么也可以使用。

『杀 / K』在自己的回合内,对攻击范围内除自己以外的 1 名角色使用。如果没有被『闪』抵消,则造成 1 点伤害。无论有无武器,杀的攻击范围都是 1。

『闪 / D』当你受到杀的攻击时,可以弃置 1 张闪来抵消杀的效果。

锦囊牌

『决斗 / F』出牌阶段,对除自己以外任意 1 名角色使用,由目标角色先开始,自己和目标角色轮流弃置 1 张杀,首先没有杀可弃的一方受到 1 点伤害,另一方视为此伤害的来源。

『南猪入侵 / N』出牌阶段,对除你以外所有角色使用,按逆时针顺序从使用者下家开始依次结算,除非弃置 1 张杀,否则受到 1 点伤害。

『万箭齐发 / W』和南猪入侵类似,不过要弃置的不是杀而是闪。

『无懈可击 / J』在目标锦囊生效前抵消其效果。每次有 1 张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会;效果:用于决斗时,决斗无效并弃置;用于南猪入侵或万箭齐发时,当结算到某个角色时才能使用,当前角色不需弃置牌并且不会受到伤害(仅对 1 个角色产生效果);用于无懈可击时,成为目标的无懈可击被无效。

装备牌

『猪哥连弩 / Z』武器,攻击范围 1 ,出牌阶段你可以使用任意张杀; 同一时刻最多只能装 1 把武器;如果先前已经有了 1 把武器,那么之后再装武器的话,会弃置以前的武器来装现在的武器。

特殊事件及概念解释

伤害来源:杀、南猪入侵、万箭齐发的伤害来源均是使用该牌的猪,决斗的伤害来源如上;

距离:两只猪的距离定义为沿着逆时针方向间隔的猪数 +1 。即初始时 1 和 2 的距离为 1 ,但是 2 和 1 的距离就是 n−1 。注意一个角色的死亡会导致一些猪距离的改变;

玩家死亡:如果该玩家的体力降到 0 或者更低,并且自己手中没有足够的桃使得自己的体力值回到 1 ,那么就死亡了,死亡后所有的牌(装备区,手牌区)被弃置

奖励与惩罚:反猪死亡时,最后一个伤害来源处(即使是反猪)立即摸 3 张牌。忠猪死亡时,如果最后一个伤害来源是主猪,那么主猪所有装备牌、手牌被弃置。

注意:一旦达成胜利条件,游戏立刻结束,因此即使会摸 3 张牌或者还有牌可以用也不用执行了。

现在,我们已经知道每只猪的角色、手牌,还有牌堆初始情况,并且假设每个角色会按照如下的行为准则进行游戏,你需要做的就是告诉最后的结果。

几种行为:

献殷勤:使用无懈可击挡下南猪入侵、万箭齐发、决斗;使用无懈可击抵消表敌意的锦囊效果;
表敌意:对某个角色使用杀、决斗;使用无懈可击抵消献殷勤的锦囊效果;
跳忠:即通过行动表示自己是忠猪。跳忠行动就是对主猪或对某只已经跳忠的猪献殷勤,或者对某只已经跳反的猪表敌意;
跳反:即通过行动表示自己是反猪。跳反行动就是对主猪或对某只已经跳忠的猪表敌意,或者对某只已经跳反的猪献殷勤。

注意:忠猪不会跳反,反猪也不会跳忠;不管是忠猪还是反猪,能够跳必然跳

行动准则

共性

  • 每个角色如果手里有桃且生命值未满,那么必然吃掉;
  • 有南猪入侵、万箭齐发、必然使用;有装备必然装上;
  • 受到杀时,有闪必然弃置;
  • 响应南猪入侵或者万箭齐发时候,有杀 / 闪必然弃置;
  • 不会对未表明身份的猪献殷勤(包括自己)。

特性

主猪:

  • 主猪会认为「没有跳身份,且用南猪入侵 / 万箭齐发对自己造成伤害的猪」是类反猪(没伤害到不算,注意类反猪并没有表明身份),如果之后跳了,那么主猪会重新认识这只猪;
  • 对于每种表敌意的方式,对逆时针方向能够执行到的第一只已跳反猪表;如果没有,对逆时针方向能够执行到的第一只类反猪表,再没有,那么就不表敌意;
  • 决斗时会不遗余力弃置杀;
  • 如果能对已经跳忠的猪或自己献殷勤,那么一定献;如果能够对已经跳反的猪表敌意,那么一定表。

忠猪:

  • 对于每种表敌意的方式,对「逆时针方向能够执行到的第一只已经跳反的猪」表,如果没有,那么就不表敌意;
    决斗时,如果对方是主猪,那么不会弃置杀,否则,会不遗余力弃置杀;
  • 如果有机会对主猪或者已经跳忠的猪献殷勤,那么一定献。

反猪:

  • 对于每种表敌意的方式,如果有机会则对主猪表,否则,对「逆时针方向能够执行到的第一只已经跳忠的猪」表,如果没有,那么就不表敌意;
  • 决斗时会不遗余力弃置杀;
  • 如果有机会对已经跳反的猪献殷勤,那么一定献。

输入格式

输入文件第一行包含两个正整数 n(2⩽n⩽10) 和 m(m⩽2000),分别代表玩家数和牌堆中牌的数量。数据保证牌的数量够用。

接下来 n 行,每行 5 个字符串,依次表示对第 i 只猪的角色和初始 4 张手牌描述。编号为 1 的肯定是主猪。

再接下来一行,一共 m 个字符串,按照从牌堆顶部到牌堆底部的顺序描述每张牌。

注意:所有的相邻的两个字符串都严格用 1 个空格隔开,行尾没有多余空格。

输出格式

输出数据第一行包含一个字符串代表游戏结果。如果是主猪胜利,那么输出 MP ,否则输出 FP 。数据保证游戏总会结束。

接下来 n 行,第 i 行是对第 i 只猪的手牌描述(注意只需要输出手牌),按照手牌从左往右的顺序输出,相邻两张牌用 1 个空格隔开,行末尾没有多余空格。如果这只猪已阵亡,那么只要输出 DEAD 即可。

注意:如果要输出手牌而没有手牌的话,那么只需输出 1 个空行。

样例

Input:

3 10
MP D D F F
ZP N N N D
FP J J J J
F F D D J J F F K D

Output:

FP
DEAD
DEAD
J J J J J J D

解释:

  • 第一回合:

    • 主猪没有目标可以表敌意;
    • 接下来忠猪使用了 3 张南猪入侵,主猪掉了 3 点体力,并认为该角色为类反猪,3 号角色尽管手里有无懈可击,但是因为自己未表明身份,所以同样不能对自己用,乖乖掉 3 点体力;
  • 下一回合:

    • 反猪无牌可出;
    • 接下来主猪对着类反猪爆发,使用 4 张决斗,忠猪死亡,结果主猪弃掉所有牌;

子任务

一共 20 组测试数据,每个点 5 分。

10% 的数据没有锦囊牌,另外 20% 的数据没有无懈可击。

测试样例

样例 1

输入:

3 25
MP K K K K
ZP Z Z Z Z
FP J J J J
K K Z Z J J K K W Z W W K Z J J K K J J K K W W W

输出:

FP
DEAD
DEAD
J J J J J J J J J J W

解答

// 杀
bool Pig::useK(){
    Pig *nxt = getNextPig(); // 获取下一只猪
    // 判断使用杀的猪是什么身份
    if(this->type == 'M'){ // 主猪
        if(nxt->jumpType == 'f' or nxt->jumpType=='F'){ // 判断下一只猪的跳的身份
            nxt->cost(this, 'D');
            return true;
        }
    }else if(this->type=='Z'){ // 忠猪
        if(nxt ->jumpType=='F'){ // 阵营为F则使用
            nxt->cost(this, 'D');
            this->jumpType = 'Z';
            return true;
        }
    }else if(this->type=='F'){ // 反猪
        if(nxt->jumpType=='Z'){ // 判断是否是忠猪阵营
            nxt->cost(this, 'D');
            this->jumpType = 'F';
            return true;
        }
    }
    return false;
}

// 南蛮入侵
bool Pig::useN() {
    for (Pig* nxt = getNextPig(); nxt != this; nxt = nxt->getNextPig()) {
        // TODO: 补全代码
        if(!nxt->findJ(this)){ // 没有人使用无懈可击
            bool dd = nxt->cost(this, 'K');
            if(!dd and nxt->type=='M' and this->jumpType==0){ // 没有跳身份
                this->jumpType = 'f';
            }
        }
    }
    return true;
}

// 万箭齐发
bool Pig::useW() {
    for (Pig* nxt = getNextPig(); nxt != this; nxt = nxt->getNextPig()) {
        // TODO: 补全代码
        if(!nxt->findJ(this)){ // 没人使用无懈可击
            bool dd = nxt->cost(this, 'D');
            if(!dd and nxt->type=='M' and this->jumpType==0){ // 没有跳身份
                this->jumpType = 'f';
            }
        }
    }
    return true;
}

// 决斗
bool Pig::useF(){
    char rr = this->type;
    // int gg = this->index; // 
    if(rr == 'Z'){ // 判断使用者身份
        int ff;
        bool pp = false;
        Pig *it;
        for (Pig* nxt = getNextPig(); nxt != this; nxt = nxt->getNextPig()) {
            if(nxt->jumpType=='F'){
                // ff = nxt->index;
                it = nxt;
                pp = true;
                break;
            }
        }
        if(!pp){
            return false;
        }
        this->jumpType = 'Z';
        if(!it->findJ(this)){ // 判断是否有人使用无懈可击
            while(true){
                if(!it->cost(this, 'K')) // 进行决斗,两个人相互出杀
                    break;
                if(!this->cost(it,'K'))
                    break;
            }
        }
        return true;
    }else if(rr == 'F'){
        this->jumpType = 'F';
        if(!ps[0].findJ(this)){ 
            while(true){
                if(!ps[0].cost(this,'K'))
                    break;
                if(!this->cost(&ps[0],'K'))
                    break;
            }
        }
        
        return true;
    }else if(rr == 'M'){
        int lf=100000, ff=100000;
        // 寻找第一个F和f
        for (Pig* nxt = getNextPig(); nxt != this; nxt = nxt->getNextPig()) {
            if(nxt->jumpType=='F'){
                if(nxt->index < ff){
                    ff = nxt->index;
                }   
            }
            if(nxt->jumpType =='f'){
                if (lf > nxt->index){
                    lf = nxt->index;
                }
            }
        }
        // 有F存在时
        if(ff < n){
            if(!ps[ff].findJ(this)){
                while(true){
                    if(!ps[ff].cost(this,'K'))
                    break;
                        // return true;
                    if(!this->cost(&ps[ff],'K'))
                    break;
                        // return true;
                }
            }
            return true;
        }else if(lf < n){ // F不存在,但是f存在时
            if(!ps[lf].findJ(this)){
                if(ps[lf].type == 'Z'){
                    ps[lf].hurt(this);
                }else{
                    while(true){
                        if(!ps[lf].cost(this,'K'))
                        // return true;
                            break;
                        if(!this->cost(&ps[lf],'K'))
                            break;
                        // return true;
                    }    
                }
            }
            return true;
        }
    }
    return false;
}

// 删除一张牌
bool Pig::del(char c){
    // Pig *nxt = getNextPig();
    // int gg = this->index;
    for (list<char>::iterator i = this->cards.begin(); i != this->cards.end();i++){ // 寻找牌
        if(c != *i)
            continue;
        else{ // 有就删除,没有就返回false
            this->cards.erase(i);
            return true;
        }
    }
    return false;
}

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值