1A?:?飛飛的賭神修煉手冊
飛飛很喜歡打牌,他決定苦練牌技,終成賭神!
飛飛有?A?×?B?張撲克牌。每張撲克牌有一個大小(整數(shù),記為 a,范圍區(qū)間是?0?到?A?-?1)和一個花色(整數(shù),記為 b,范圍區(qū)間是?0?到?B?-?1。
撲克牌是互異的,也就是獨一無二的,也就是說沒有兩張牌大小和花色都相同。
“一手牌”的意思是你手里有 5 張不同的牌,這 5 張牌沒有誰在前誰在后的順序之分,它們可以形成一個牌型。 我們定義了 9 種牌型,如下是 9 種牌型的規(guī)則,我們用“低序號優(yōu)先”來匹配牌型,即這“一手牌”從上到下滿足的第一個牌型規(guī)則就是它的“牌型編號”(一個整數(shù),屬于 1 到 9):
- 同花順: 同時滿足規(guī)則 5 和規(guī)則 4.
- 炸彈 : 5張牌其中有4張牌的大小相等.
- 三帶二 : 5張牌其中有3張牌的大小相等,且另外2張牌的大小也相等.
- 同花 : 5張牌都是相同花色的.
- 順子 : 5張牌的大小形如?x,?x?+?1,?x?+?2,?x?+?3,?x?+?4
- 三條: 5張牌其中有3張牌的大小相等.
- 兩對: 5張牌其中有2張牌的大小相等,且另外3張牌中2張牌的大小相等.
- 一對: 5張牌其中有2張牌的大小相等.
- 要不起: 這手牌不滿足上述的牌型中任意一個.
現(xiàn)在, 飛飛從?A?×?B?張撲克牌中拿走了 2 張牌!分別是?(a1,?b1)?和?(a2,?b2). (其中a表示大小,b表示花色)
現(xiàn)在要從剩下的撲克牌中再隨機拿出 3 張!組成一手牌??!
其實飛飛現(xiàn)在要預(yù)言他的未來的可能性,即他將拿到的“一手牌”的可能性,我們用一個 “牌型編號(一個整數(shù),屬于 1 到 9)” 來表示這手牌的牌型,那么他的未來有 9 種可能,但每種可能的方案數(shù)不一樣。
現(xiàn)在飛飛想要計算一下 9 種牌型中,每種牌型的方案數(shù)。
Input
第?1?行包含了整數(shù)?A?和?B?(1?≤?A?≤?25,?1?≤?B?≤?4).
第?2?行包含了整數(shù)?a1,?b1,?a2,?b2?(0?≤?a1,?a2?≤?A?-?1,?0?≤?b1,?b2?≤?B?-?1,?(a1,?b1)?≠?(a2,?b2)).
Output
輸出一行,這行有 9 個整數(shù),每個整數(shù)代表了 9 種牌型的方案數(shù)(按牌型編號從小到大的順序)
限制:設(shè)計程序進(jìn)行枚舉,不能使用數(shù)學(xué)公式推導(dǎo)出每種牌型的方案數(shù)式子!
限制:設(shè)計程序進(jìn)行枚舉,不能使用數(shù)學(xué)公式推導(dǎo)出每種牌型的方案數(shù)式子!
限制:設(shè)計程序進(jìn)行枚舉,不能使用數(shù)學(xué)公式推導(dǎo)出每種牌型的方案數(shù)式子!
測試樣例
樣例 1
輸入:文章來源:http://www.zghlxwxcb.cn/news/detail-418515.html
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的個數(shù)
int hh = 0; // 花色相同的個數(shù)
int y = 0; // 三張牌相同的個數(shù)
int yy = 0; // 前后數(shù)字相同的個數(shù)
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 成為了助教,他就熱衷于給同學(xué)們解答疑問,于是他就沒有時間進(jìn)行陪他的貓貓玩了,真是一只可憐的小貓。
TT 在同一時間會與很多同學(xué)同時用 QQ(TT 特供版) 進(jìn)行答疑,有時 TT?開啟一個新的窗口,開始一個新的答疑對話;有時 TT?關(guān)閉一個窗口,結(jié)束一段答疑; 有時,為了及時回答著急的同學(xué),TT 會把一個對話窗口設(shè)置為置頂狀態(tài)(置頂狀態(tài)是一種虛擬的狀態(tài),窗口的實際位置并不會發(fā)生改變)。
你可以將 TT 的聊天窗口想象成一個隊列。如果現(xiàn)在沒有窗口處于置頂狀態(tài),那么在隊列中位列第一窗口視為在頂層,否則處于置頂狀態(tài)的窗口視為在頂層。請注意,不可能同時存在兩個窗口處于置頂狀態(tài)(也就是說,處于置頂狀態(tài)的窗口,要么不存在,要么只有一個)。如果當(dāng)前置頂的窗口被關(guān)閉了,則剩余隊列中第一窗口視為在頂層。
TT 為了安撫自己的貓,于是給貓貓看自己的聊天記錄解悶,根據(jù)貓貓看屏幕中窗口的時間,TT 給每個窗口分配了一個喜愛度,TT 認(rèn)為喜愛度越高,貓貓越開心。由于貓貓具有不確定的生物特性,所以所有的喜愛度都是不同的。
作為 TT 特供版 QQ 的研發(fā)人員,你要負(fù)責(zé)完成的工作是為軟件記錄 TT 的操作,形成一個日志系統(tǒng)。日志有固定的記錄格式:OpId #X: MSG.
?,其中?X?是操作的編號,而?MSG
?是日志的提示信息,需要使用特定的字符串進(jìn)行替換。
TT 可能會用到的操作如下:
-
Add u:?TT 打開一個喜愛度為?u?的新窗口,若?u?不與當(dāng)前窗口隊列中的某個窗口重復(fù),則該新窗口將新建成功,并成為窗口隊列中的最后一個窗口。 如果創(chuàng)建成功,則?
MSG
?記錄?success
。 否則,?MSG
?記錄?same likeness
。 -
Close u:?TT 關(guān)掉了一個喜愛度為?u?的窗口,如果該窗口存在,則將其關(guān)閉,
MSG
?記錄?close u with c
,u?表示喜愛度,c?表示該窗口上次打開至今交流的話的數(shù)量。若該窗口不存在,則?MSG
?記錄?invalid likeness
。 -
Chat w:?TT 和頂層窗口交流了?w?句話,如果當(dāng)前隊列中沒有窗口,則?
MSG
?記錄?empty
,否則記錄?success
。 -
Rotate x:?將隊列中第?x?個窗口放在隊首,若?x?大于當(dāng)前隊列中窗口數(shù)或小于?1?,則?
MSG
?記錄?out of range
,否則記錄?success
。舉個例子,目前隊列中有喜愛度為 5,3,2,8 的四個窗口,Rotate 3 之后,會將喜愛度為 2 的第 3 個窗口放在首位,結(jié)果為 2,5,3,8。 -
Prior:?TT 將目前喜愛度最大的窗口放在隊首,如果當(dāng)前隊列中沒有窗口,則?
MSG
?記錄?empty
,否則記錄?success
。 -
Choose u:?TT 將喜愛度為?u?的窗口放在隊首,如果喜愛度為?u?的窗口存在,則?
MSG
?記錄?success
,否則記錄?invalid likeness
。 -
Top u:?TT 將喜愛度為?u?的窗口設(shè)定為置頂狀態(tài),如果喜愛度為?u?的窗口存在,則?
MSG
?記錄?success
,否則記錄?invalid likeness
。注意,處于置頂狀態(tài)的窗口最多不超過一個,也就是說,如果在此次設(shè)定前已經(jīng)有處于置頂狀態(tài)的窗口,則原有置頂狀態(tài)的窗口的置頂狀態(tài)將會消失。(置頂只是一種虛擬的狀態(tài),原窗口在隊列中的位置不會發(fā)生變化) -
Untop:?TT 取消當(dāng)前處于置頂狀態(tài)窗口的置頂狀態(tài)。如果當(dāng)前沒有窗口處于置頂狀態(tài),則?
MSG
?記錄?no such person
,否則記錄?success
。
最后,由于 TT 要給自己的貓貓樹立一個講文明有禮貌的榜樣,所以在上述操作完成后,還要進(jìn)行若干次操作,這些操作是:與當(dāng)前隊列中所有說過話的窗口說拜拜。MSG
?記錄?Bye u: c
,?u?表示喜愛度,c?表示該窗口上次打開至今交流的話的數(shù)量。即:TT 先和位于頂層的窗口說拜拜,然后將其關(guān)閉,如果 TT 沒有和當(dāng)前頂層窗口說過話,則直接將其關(guān)閉,如此操作下去,直到隊列為空。
輸入描述
第一行包含一個整數(shù)?T(T≤5),表示數(shù)據(jù)組數(shù)。
對于每組數(shù)據(jù),第一行一個?n,表示執(zhí)行的操作數(shù),其中?0<n≤5000。接下來?n?行,每行輸入一個操作,保證所有輸入數(shù)據(jù)中的整數(shù)不大于?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; // 置頂?shù)拇翱诘男蛱?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 :?記事本
注:本題有較多的部分分,請參看數(shù)據(jù)規(guī)模部分。
題目描述
記事本是 Windows 平臺下一款經(jīng)典的文本編輯器,其存儲文件的擴展名為?.txt
,文件屬性沒有任何格式標(biāo)簽或者風(fēng)格,所以相當(dāng)適合在 DOS 環(huán)境中編輯。
在本題中,可能會用到的按鍵如下圖所示:
光標(biāo)移動
光標(biāo)表示當(dāng)前要進(jìn)行輸入等操作的位置,在本題中,我們假設(shè)所有字符都是等寬的。
光標(biāo)的位置可以用行列坐標(biāo)來描述,光標(biāo)所在的行和列均從 1 開始,例如:
以下操作可以進(jìn)行光標(biāo)的移動,使用?MOVE <comd>
?輸入相關(guān)的操作,其中?<comd>
?表示指令,可以使用以下字符串代替:
-
Home
:把光標(biāo)移動到當(dāng)前行的開頭。 -
End
:把光標(biāo)移動到當(dāng)前行的末尾。 -
Up
:光標(biāo)移動到上一行的相同列。- 若當(dāng)前為第一行,則不進(jìn)行任何操作。
- 若上一行的列數(shù)小于當(dāng)前光標(biāo)的列數(shù),則將光標(biāo)移動到上一行的末尾。
-
Down
:光標(biāo)移動到下一行的相同列。- 若當(dāng)前為最后一行,則不進(jìn)行任何操作。
- 若下一行的列數(shù)小于當(dāng)前光標(biāo)的列數(shù),則將光標(biāo)移動到下一行的末尾。
-
Left
:光標(biāo)左移一位。- 若當(dāng)前光標(biāo)位于記事本開始,則不進(jìn)行任何操作。
- 若當(dāng)前光標(biāo)處于某一行的開頭,則將光標(biāo)移動到上一行的末尾。
-
Right
:光標(biāo)右移一位。- 若當(dāng)前光標(biāo)位于記事本末尾,則不進(jìn)行任何操作。
- 若當(dāng)前光標(biāo)處于某一行的末尾,則將光標(biāo)移動到下一行的開頭。
輸入
以下操作可以在光標(biāo)后進(jìn)行輸入,使用?INSERT <comd>
?輸入相關(guān)的操作,其中?<comd>
?表示指令,可以使用以下字符串代替:
-
Char <char>
:輸入一個字符,其中?<char>
?是輸入的字符。-
<char>
?可能是一下字符中的任意一個:
注:下列字符中不包含空格與換行符。
`1234567890-=~!@#$%^&*()_+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:"zxcvbnm,./ZXCVBNM<>?
- 例如:
INSERT Char a
?表示在當(dāng)前光標(biāo)后插入?a
?字符。
-
-
Enter
:輸入換行符,并進(jìn)行換行。 -
Space
:輸入空格。 -
Paste
:在當(dāng)前光標(biāo)后,插入粘貼板中的內(nèi)容,若粘貼板中無內(nèi)容,則忽略當(dāng)前操作。
刪除
以下操作可以刪除記事本中的內(nèi)容,使用?REMOVE <comd>
?輸入相關(guān)的操作,其中?<comd>
?表示指令,可以使用以下字符串代替:
-
Del
:刪除當(dāng)前光標(biāo)位置之后的一個字符。- 若該字符為換行符,則當(dāng)前行與下一行合并為一行。
- 若當(dāng)前光標(biāo)在文件末尾,則忽略當(dāng)前操作。
-
Backspace
:刪除當(dāng)前光標(biāo)位置之前的一個字符。- 若該字符為換行符,則當(dāng)前行與上一行合并為一行。
- 若當(dāng)前光標(biāo)在文件開頭,則忽略當(dāng)前操作。
粘滯功能(分?jǐn)?shù)占比 24 分)
輸入?SHIFT
?指令,可以啟動或關(guān)閉粘滯功能。
-
開始時粘滯功能默認(rèn)為關(guān)閉狀態(tài),之后每次點擊:
- 若當(dāng)前為啟動狀態(tài),則關(guān)閉;
- 若當(dāng)前為關(guān)閉狀態(tài),則啟動。
-
粘滯功能啟動時,記錄當(dāng)前的光標(biāo)位置為?記錄點。
-
粘滯功能關(guān)閉時,若此時的光標(biāo)位置與?記錄點?的位置不同,則進(jìn)入選中狀態(tài)。
-
粘滯功能啟動后,直到功能關(guān)閉前,不會對記事本進(jìn)行除光標(biāo)移動外的任何操作。
當(dāng)進(jìn)入選中狀態(tài)后,通過記錄點與當(dāng)前光標(biāo),可以唯一的確定一段內(nèi)容,現(xiàn)令記錄點與光標(biāo)之間的所有字符(包括換行符)為?選中字段。
例如,記錄點位于第 1 行第 2 列,光標(biāo)位于第 2 行第 4 列時,選中字段如下圖所示:
當(dāng)前?處于選中狀態(tài)?時,對于不同的情況,需要按照序號依次執(zhí)行以下操作:
-
若進(jìn)行光標(biāo)移動:
- 退出選中狀態(tài);
- 嘗試進(jìn)行光標(biāo)的移動(無論光標(biāo)最終是否移動,都會退出選中狀態(tài))。
-
若進(jìn)行輸入:
- 將選中內(nèi)容替換為輸入內(nèi)容;
- 退出選中狀態(tài)。
-
若進(jìn)行刪除:
- 刪除當(dāng)前選中內(nèi)容;
- 退出選中狀態(tài)。
-
若再次啟動粘滯功能:退出選中狀態(tài),但保留上一次選中字段的?記錄點?作為當(dāng)前記錄點。
-
若進(jìn)行查找,字?jǐn)?shù)統(tǒng)計,復(fù)制,打印操作,則在操作后仍然保持選中狀態(tài)。
查找
輸入?FIND <word>
?指令,進(jìn)行字符串查找,其中?<word>
?為輸入的要查找的字符串,該字符串中不包含空格與換行符。
執(zhí)行該指令時,要根據(jù)當(dāng)前是否處于選中狀態(tài)做不同的處理:
- 若當(dāng)前處于選中狀態(tài):查找輸入字符串在選中字段中的出現(xiàn)次數(shù)并輸出。
- 否則:查找輸入字符串在當(dāng)前記事本中的出現(xiàn)次數(shù)并輸出。
例如:當(dāng)前沒有選中的內(nèi)容,且記事本中的內(nèi)容為?ababa
,若執(zhí)行?FIND aba
,則應(yīng)當(dāng)輸出 2,分別在第 1 列與第 3 列出現(xiàn)過。
字?jǐn)?shù)統(tǒng)計
輸入?COUNT
?指令,進(jìn)行字?jǐn)?shù)統(tǒng)計。
執(zhí)行該指令時,要根據(jù)當(dāng)前是否處于選中狀態(tài)做不同的處理:
- 若當(dāng)前處于選中狀態(tài):輸出當(dāng)前選中字段中的可見字符(不包括空格與換行符)的數(shù)量。
- 否則:輸出當(dāng)前文檔中可見字符(不包括空格與換行符)的數(shù)量。
復(fù)制
輸入?COPY
?指令,進(jìn)行復(fù)制操作。
執(zhí)行該指令時,要根據(jù)當(dāng)前是否處于選中狀態(tài)做不同的處理:
- 若當(dāng)前處于選中狀態(tài):復(fù)制選中字段到粘貼板;
- 否則,
- 若當(dāng)前行不為空:復(fù)制當(dāng)前行的內(nèi)容(不包括換行符)到粘貼板;
- 否則:忽略當(dāng)前操作。
打印
輸入?PRINT
?指令,輸出當(dāng)前的記事本中的全部內(nèi)容,并在之后輸出一個換行符。
輸入格式
輸入包含?n+1?行。
第一行包含一個整數(shù)?n,表示接下來指令的數(shù)量。
接下來?n?行,每行一條指令,格式形如題目描述中的敘述。
輸出格式
對于需要輸出的指令,進(jìn)行相應(yīng)的輸出。
若為?FIND
?與?COUNT
?操作,輸出一行表示相應(yīng)的數(shù)字。
若為?PRINT
?操作,則輸出若干行,表示記事本的當(dāng)前內(nèi)容,并在之后輸出一個換行。
請注意:所有的輸出不要有多余的空格。
測試樣例
樣例輸入
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
數(shù)據(jù)規(guī)模
對于?100%?的測試數(shù)據(jù),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 :?豬國殺(模板)
請使用指定的代碼模板完成該題~
- 由于原題在題面和數(shù)據(jù)上的一些小問題,本題經(jīng)過了一些小修小改,數(shù)據(jù),和題面,與 SDOI2010 略有不同。參考網(wǎng)絡(luò)資料將讓你在完成作業(yè)的路徑上繞遠(yuǎn)路(不保證可行)并且收獲甚少。相信自己,獨立完成會收獲很多,你也可以在思考無所獲后向同學(xué)請教。
- 代碼模板精心制作,請大家理解后進(jìn)行補全代碼實驗
- 本題代碼模板不嚴(yán)格遵守面向?qū)ο蟮囊?guī)則,而是面向教育用途設(shè)計
- 比起費力優(yōu)化代碼的常數(shù)復(fù)雜度,更樂于精心設(shè)計將代碼邏輯區(qū)分開
- 本實驗考點:
- 問題理解及其邏輯化能力
- 大型(顯然并不大?第三方代碼框架理解和分析能力
- 工程改動的創(chuàng)口分析和實踐能力
- 程序調(diào)試能力
- 期末將近,預(yù)祝同學(xué)們期末考得好成績,不負(fù)努力,加油。
背景
《豬國殺》是一種多豬牌類回合制游戲,一共有 3 種角色:主豬,忠豬,反豬。每局游戲主豬有且只有 1 只,忠豬和反豬可以有多只,每只豬扮演 1 種角色。
目的
主豬 / MP:自己存活的情況下消滅所有的反豬。
忠豬 / ZP:不惜一切保護(hù)主豬,勝利條件與主豬相同。
反豬 / FP:殺死主豬。
游戲過程
游戲開始時,每個玩家手里都會有 4 張牌,且體力上限和初始體力都是 4 。
開始游戲時,從主豬開始,按照逆時針方向(數(shù)據(jù)中就是按照編號從?1,2,3…n?的順序)依次行動。
每個玩家自己的回合可以分為 2 個階段:
- 摸牌階段:從牌堆頂部摸 2 張牌,依次放到手牌的最右邊;
- 出牌階段:你可以使用任意張牌,每次使用牌的時候都使用最靠左的能夠使用的牌。當(dāng)然,要滿足如下規(guī)則:
- 如果沒有豬哥連弩,每個出牌階段只能使用 1 次「殺」來攻擊;
- 任何牌被使用后被棄置(武器是裝備上);被棄置的牌以后都不能再用,即與游戲無關(guān)。
各種牌介紹
每張手牌用 1 個字母表示,字母代表牌的種類。
基本牌
『桃 / P』在自己的回合內(nèi),如果自己的體力值不等于體力上限,那么使用 1 個桃可以為自己補充 1 點體力,否則不能使用桃;桃只能對自己使用;在自己的回合外,如果自己的血變?yōu)?0 或者更低,那么也可以使用。
『殺 / K』在自己的回合內(nèi),對攻擊范圍內(nèi)除自己以外的 1 名角色使用。如果沒有被『閃』抵消,則造成 1 點傷害。無論有無武器,殺的攻擊范圍都是 1。
『閃 / D』當(dāng)你受到殺的攻擊時,可以棄置 1 張閃來抵消殺的效果。
錦囊牌
『決斗 / F』出牌階段,對除自己以外任意 1 名角色使用,由目標(biāo)角色先開始,自己和目標(biāo)角色輪流棄置 1 張殺,首先沒有殺可棄的一方受到 1 點傷害,另一方視為此傷害的來源。
『南豬入侵 / N』出牌階段,對除你以外所有角色使用,按逆時針順序從使用者下家開始依次結(jié)算,除非棄置 1 張殺,否則受到 1 點傷害。
『萬箭齊發(fā) / W』和南豬入侵類似,不過要棄置的不是殺而是閃。
『無懈可擊 / J』在目標(biāo)錦囊生效前抵消其效果。每次有 1 張錦囊即將生效時,從使用這張錦囊的豬開始,按照逆時針順序,依次得到使用無懈可擊的機會;效果:用于決斗時,決斗無效并棄置;用于南豬入侵或萬箭齊發(fā)時,當(dāng)結(jié)算到某個角色時才能使用,當(dāng)前角色不需棄置牌并且不會受到傷害(僅對 1 個角色產(chǎn)生效果);用于無懈可擊時,成為目標(biāo)的無懈可擊被無效。
裝備牌
『豬哥連弩 / Z』武器,攻擊范圍 1 ,出牌階段你可以使用任意張殺; 同一時刻最多只能裝 1 把武器;如果先前已經(jīng)有了 1 把武器,那么之后再裝武器的話,會棄置以前的武器來裝現(xiàn)在的武器。
特殊事件及概念解釋
傷害來源:殺、南豬入侵、萬箭齊發(fā)的傷害來源均是使用該牌的豬,決斗的傷害來源如上;
距離:兩只豬的距離定義為沿著逆時針方向間隔的豬數(shù) +1 。即初始時 1 和 2 的距離為 1 ,但是 2 和 1 的距離就是 n?1 。注意一個角色的死亡會導(dǎo)致一些豬距離的改變;
玩家死亡:如果該玩家的體力降到 0 或者更低,并且自己手中沒有足夠的桃使得自己的體力值回到 1 ,那么就死亡了,死亡后所有的牌(裝備區(qū),手牌區(qū))被棄置
獎勵與懲罰:反豬死亡時,最后一個傷害來源處(即使是反豬)立即摸 3 張牌。忠豬死亡時,如果最后一個傷害來源是主豬,那么主豬所有裝備牌、手牌被棄置。
注意:一旦達(dá)成勝利條件,游戲立刻結(jié)束,因此即使會摸 3 張牌或者還有牌可以用也不用執(zhí)行了。
現(xiàn)在,我們已經(jīng)知道每只豬的角色、手牌,還有牌堆初始情況,并且假設(shè)每個角色會按照如下的行為準(zhǔn)則進(jìn)行游戲,你需要做的就是告訴最后的結(jié)果。
幾種行為:
獻(xiàn)殷勤:使用無懈可擊擋下南豬入侵、萬箭齊發(fā)、決斗;使用無懈可擊抵消表敵意的錦囊效果;
表敵意:對某個角色使用殺、決斗;使用無懈可擊抵消獻(xiàn)殷勤的錦囊效果;
跳忠:即通過行動表示自己是忠豬。跳忠行動就是對主豬或?qū)δ持灰呀?jīng)跳忠的豬獻(xiàn)殷勤,或者對某只已經(jīng)跳反的豬表敵意;
跳反:即通過行動表示自己是反豬。跳反行動就是對主豬或?qū)δ持灰呀?jīng)跳忠的豬表敵意,或者對某只已經(jīng)跳反的豬獻(xiàn)殷勤。
注意:忠豬不會跳反,反豬也不會跳忠;不管是忠豬還是反豬,能夠跳必然跳。
行動準(zhǔn)則
共性
- 每個角色如果手里有桃且生命值未滿,那么必然吃掉;
- 有南豬入侵、萬箭齊發(fā)、必然使用;有裝備必然裝上;
- 受到殺時,有閃必然棄置;
- 響應(yīng)南豬入侵或者萬箭齊發(fā)時候,有殺 / 閃必然棄置;
- 不會對未表明身份的豬獻(xiàn)殷勤(包括自己)。
特性
主豬:
- 主豬會認(rèn)為「沒有跳身份,且用南豬入侵 / 萬箭齊發(fā)對自己造成傷害的豬」是類反豬(沒傷害到不算,注意類反豬并沒有表明身份),如果之后跳了,那么主豬會重新認(rèn)識這只豬;
- 對于每種表敵意的方式,對逆時針方向能夠執(zhí)行到的第一只已跳反豬表;如果沒有,對逆時針方向能夠執(zhí)行到的第一只類反豬表,再沒有,那么就不表敵意;
- 決斗時會不遺余力棄置殺;
- 如果能對已經(jīng)跳忠的豬或自己獻(xiàn)殷勤,那么一定獻(xiàn);如果能夠?qū)σ呀?jīng)跳反的豬表敵意,那么一定表。
忠豬:
- 對于每種表敵意的方式,對「逆時針方向能夠執(zhí)行到的第一只已經(jīng)跳反的豬」表,如果沒有,那么就不表敵意;
決斗時,如果對方是主豬,那么不會棄置殺,否則,會不遺余力棄置殺; - 如果有機會對主豬或者已經(jīng)跳忠的豬獻(xiàn)殷勤,那么一定獻(xiàn)。
反豬:
- 對于每種表敵意的方式,如果有機會則對主豬表,否則,對「逆時針方向能夠執(zhí)行到的第一只已經(jīng)跳忠的豬」表,如果沒有,那么就不表敵意;
- 決斗時會不遺余力棄置殺;
- 如果有機會對已經(jīng)跳反的豬獻(xiàn)殷勤,那么一定獻(xiàn)。
輸入格式
輸入文件第一行包含兩個正整數(shù)?n(2?n?10)?和?m(m?2000),分別代表玩家數(shù)和牌堆中牌的數(shù)量。數(shù)據(jù)保證牌的數(shù)量夠用。
接下來 n 行,每行 5 個字符串,依次表示對第 i 只豬的角色和初始 4 張手牌描述。編號為 1 的肯定是主豬。
再接下來一行,一共 m 個字符串,按照從牌堆頂部到牌堆底部的順序描述每張牌。
注意:所有的相鄰的兩個字符串都嚴(yán)格用 1 個空格隔開,行尾沒有多余空格。
輸出格式
輸出數(shù)據(jù)第一行包含一個字符串代表游戲結(jié)果。如果是主豬勝利,那么輸出 MP ,否則輸出 FP 。數(shù)據(jù)保證游戲總會結(jié)束。
接下來 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
解釋:
-
第一回合:
- 主豬沒有目標(biāo)可以表敵意;
- 接下來忠豬使用了 3 張南豬入侵,主豬掉了 3 點體力,并認(rèn)為該角色為類反豬,3 號角色盡管手里有無懈可擊,但是因為自己未表明身份,所以同樣不能對自己用,乖乖掉 3 點體力;
-
下一回合:
- 反豬無牌可出;
- 接下來主豬對著類反豬爆發(fā),使用 4 張決斗,忠豬死亡,結(jié)果主豬棄掉所有牌;
子任務(wù)
一共 20 組測試數(shù)據(jù),每個點 5 分。
10% 的數(shù)據(jù)沒有錦囊牌,另外 20% 的數(shù)據(jù)沒有無懈可擊。
測試樣例
樣例 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
輸出:文章來源地址http://www.zghlxwxcb.cn/news/detail-418515.html
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;
}
// 萬箭齊發(fā)
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')) // 進(jìn)行決斗,兩個人相互出殺
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;
}
到了這里,關(guān)于Vj程序設(shè)計復(fù)雜模擬題訓(xùn)練的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!