diff --git a/P2482.cpp b/P2482.cpp new file mode 100644 index 0000000..134fb14 --- /dev/null +++ b/P2482.cpp @@ -0,0 +1,478 @@ +#include +using namespace std; + +int n, m; +char js[15]; // 角色:M主猪, Z忠猪, F反猪 +char p[15][10005]; // 手牌 +int l[15], r[15]; // 手牌左右边界(闭区间) +vector dui; // 牌堆(尾部为堆顶) +int stre[15]; // 体力值 +int fro[15], nex[15]; // 双向链表,用于存活角色遍历 +bool zgln[15]; // 是否装备诸葛连弩 +bool tiao[15]; // 是否已跳身份(忠/反表明) +bool lei[15]; // 主猪的类反猪标记 +char last_card = 'P'; // 牌堆最后一张(初始为桃,避免空堆摸到空字符) + +inline char read() +{ + char ch = getchar(); + while (ch < 'A' || ch > 'Z') + ch = getchar(); + return ch; +} + +void init() +{ + scanf("%d %d\n", &n, &m); + for (int i = 0; i < n; ++i) + { + js[i] = read(); + read(); // 跳过空格 + for (int j = 0; j < 4; ++j) + p[i][j] = read(); + stre[i] = 4; + l[i] = 0; + r[i] = 3; + fro[i] = (i == 0) ? (n - 1) : (i - 1); + nex[i] = (i + 1) % n; + } + for (int i = 0; i < m; ++i) + dui.push_back(read()); + reverse(dui.begin(), dui.end()); // 牌堆尾部为堆顶 +} + +int pd() +{ + bool fp_alive = false; + for (int i = 0; i < n; ++i) + if (js[i] == 'F' && stre[i] > 0) + { + fp_alive = true; + break; + } + if (stre[0] <= 0) + return 2; // FP胜 + if (!fp_alive) + return 1; // MP胜 + return 0; // 未结束 +} + +void mp(int now, int cnt) +{ + while (cnt--) + { + if (!dui.empty()) + { + last_card = dui.back(); + dui.pop_back(); + } + p[now][++r[now]] = last_card; + } +} + +void dealdead(int now, int from) +{ + // 濒死求桃 + if (stre[now] <= 0) + { + for (int j = l[now]; j <= r[now]; ++j) + if (p[now][j] == 'P') + { + stre[now]++; + p[now][j] = 0; + if (stre[now] > 0) + break; + } + } + if (stre[now] <= 0) + { + // 死亡处理:从存活链表中移除 + if (now != 0) + { + nex[fro[now]] = nex[now]; + fro[nex[now]] = fro[now]; + } + // 奖惩:仅在游戏未结束时执行 + if (pd() == 0) + { + if (js[now] == 'F') + { + mp(from, 3); + } + else if (js[now] == 'Z' && js[from] == 'M') + { + // 主猪弃掉所有手牌和装备 + for (int j = l[from]; j <= r[from]; ++j) + p[from][j] = 0; + l[from] = 0; + r[from] = -1; + zgln[from] = false; + } + } + // 死亡猪自己的手牌全部弃置 + for (int j = l[now]; j <= r[now]; ++j) + p[now][j] = 0; + l[now] = 0; + r[now] = -1; + zgln[now] = false; + } +} + +/* ---------- 无懈可击相关函数 ---------- */ +int findJ(int now) +{ + for (int i = l[now]; i <= r[now]; ++i) + if (p[now][i] == 'J') + return i; + return -1; +} +void useJ(int now) +{ + int pos = findJ(now); + if (pos != -1) p[now][pos] = 0; +} + +// 判断 now 是否会对 target 使用无懈可击,isProtect=true 表示献殷勤,false 表示表敌意 +bool canUseJ(int now, int target, bool isProtect) +{ + if (isProtect) + { + // 献殷勤:不会对未表明身份的猪(包括自己),主猪视为已表明 + if (!(tiao[target] || js[target] == 'M')) return false; + if (js[now] == 'M') + return (target == now) || (js[target] == 'Z' && tiao[target]); + else if (js[now] == 'Z') + return (target == 0) || (js[target] == 'Z' && tiao[target]); + else if (js[now] == 'F') + return (js[target] == 'F' && tiao[target]); + } + else + { + // 表敌意 + if (js[now] == 'M') + return (js[target] == 'F' && tiao[target]); + else if (js[now] == 'Z') + return (js[target] == 'F' && tiao[target]); + else if (js[now] == 'F') + return (target == 0) || (js[target] == 'Z' && tiao[target]); + } + return false; +} + +// 询问链:当前牌的使用者 user,目标 target,isProtect 表示当前牌是保护(true)还是攻击(false) +// 返回 true 表示当前牌被无懈可击抵消 +bool askWJ(int user, int target, bool isProtect) +{ + if (pd() != 0) return false; + int cur = user; + do + { + if (stre[cur] <= 0) { cur = nex[cur]; continue; } + if (findJ(cur) == -1) { cur = nex[cur]; continue; } + + bool willProtect; + int jTarget; + if (!isProtect) // 当前牌是攻击(锦囊),出J是保护 + { + willProtect = true; + jTarget = target; + } + else // 当前牌是保护(J),出J是攻击 + { + willProtect = false; + jTarget = user; + } + + if (canUseJ(cur, jTarget, willProtect)) + { + useJ(cur); // 弃置最左的J + + // 跳身份处理 + if (willProtect) // 献殷勤 + { + if (js[cur] == 'Z' && (jTarget == 0 || (js[jTarget] == 'Z' && tiao[jTarget]))) + tiao[cur] = true, lei[cur] = false; + else if (js[cur] == 'F' && (js[jTarget] == 'F' && tiao[jTarget])) + tiao[cur] = true, lei[cur] = false; + // 主猪献殷勤不需跳身份 + } + else // 表敌意 + { + if (js[cur] == 'Z' && js[jTarget] == 'F' && tiao[jTarget]) + tiao[cur] = true, lei[cur] = false; + else if (js[cur] == 'F' && (jTarget == 0 || (js[jTarget] == 'Z' && tiao[jTarget]))) + tiao[cur] = true, lei[cur] = false; + // 主猪表敌意给已跳反猪,若目标有类反标记则清除 + if (js[cur] == 'M' && js[jTarget] == 'F' && tiao[jTarget]) + lei[jTarget] = false; + } + + // 递归:询问是否有人无懈可击这张J + if (!askWJ(cur, jTarget, willProtect)) // 这张J没有被抵消 → 成功抵消当前牌 + return true; + // 否则J被抵消,继续循环询问下一个猪 + } + cur = nex[cur]; + } while (cur != user); + return false; +} + +/* ---------- 锦囊结算 ---------- */ +void NW(int now, char KD) // 南蛮/万箭 +{ + int cur = nex[now]; + while (cur != now) + { + if (stre[cur] <= 0) { cur = nex[cur]; continue; } + + // 无懈可击抵消此次范围伤害 + if (askWJ(now, cur, false)) + { + cur = nex[cur]; + continue; + } + + bool kou = true; + for (int j = l[cur]; j <= r[cur]; ++j) + if (p[cur][j] == KD) + { + p[cur][j] = 0; + kou = false; + break; + } + if (kou) + { + stre[cur]--; + if (cur == 0 && !tiao[now]) + lei[now] = 1; + dealdead(cur, now); + if (pd()) return; + } + cur = nex[cur]; + } +} + +void do_K(int now, int obj) +{ + // 跳身份 + if (js[now] == 'Z' && js[obj] == 'F' && tiao[obj]) + tiao[now] = true, lei[now] = false; + if (js[now] == 'F' && (js[obj] == 'M' || (js[obj] == 'Z' && tiao[obj]))) + tiao[now] = true, lei[now] = false; + + bool kou = true; + for (int i = l[obj]; i <= r[obj]; ++i) + if (p[obj][i] == 'D') + { + p[obj][i] = 0; + kou = false; + break; + } + if (kou) + { + stre[obj]--; + dealdead(obj, now); + } +} + +bool haveK(int now) +{ + for (int i = l[now]; i <= r[now]; ++i) + if (p[now][i] == 'K') + { + p[now][i] = 0; + return true; + } + return false; +} + +void do_F(int now, int obj) +{ + // 跳身份 + if (js[now] == 'Z' && js[obj] == 'F' && tiao[obj]) + tiao[now] = true, lei[now] = false; + if (js[now] == 'F' && (js[obj] == 'M' || (js[obj] == 'Z' && tiao[obj]))) + tiao[now] = true, lei[now] = false; + + // 无懈可击抵消决斗 + if (askWJ(now, obj, false)) + return; // 决斗无效 + + bool turn = false; // false=obj先出杀 + while (true) + { + int cur = turn ? now : obj; + int opp = turn ? obj : now; + if (js[cur] == 'Z' && js[opp] == 'M') + break; + if (haveK(cur)) + turn = !turn; + else + break; + } + if (turn) + { + stre[now]--; + dealdead(now, obj); + } + else + { + stre[obj]--; + dealdead(obj, now); + } +} + +void cp(int now) +{ + bool usedK = false; + int F_target = -1; + while (pd() == 0 && stre[now] > 0) + { + int pos = -1; + for (int i = l[now]; i <= r[now]; ++i) + { + if (p[now][i] == 0) continue; + char c = p[now][i]; + if (c == 'P' && stre[now] < 4) + { + pos = i; break; + } + if (c == 'Z') + { + pos = i; break; + } + if (c == 'N' || c == 'W') + { + pos = i; break; + } + if (c == 'K') + { + int obj = nex[now]; + if (stre[obj] > 0) + { + bool ok = false; + if (js[now] == 'M') + ok = (js[obj] == 'F' && tiao[obj]) || (!tiao[obj] && lei[obj]); + else if (js[now] == 'Z') + ok = (js[obj] == 'F' && tiao[obj]); + else if (js[now] == 'F') + ok = (obj == 0) || (js[obj] == 'Z' && tiao[obj]); + if (ok && (!usedK || zgln[now])) + { + pos = i; break; + } + } + } + if (c == 'F') + { + int obj = -1; + if (js[now] == 'M') + { + for (int j = nex[now]; j != now; j = nex[j]) + { + if (stre[j] <= 0) continue; + if ((js[j] == 'F' && tiao[j]) || (!tiao[j] && lei[j])) + { obj = j; break; } + } + } + else if (js[now] == 'Z') + { + for (int j = nex[now]; j != now; j = nex[j]) + { + if (stre[j] <= 0) continue; + if (js[j] == 'F' && tiao[j]) + { obj = j; break; } + } + } + else if (js[now] == 'F') + { + if (stre[0] > 0) obj = 0; + else + { + for (int j = nex[now]; j != now; j = nex[j]) + { + if (stre[j] <= 0) continue; + if (js[j] == 'M' || (js[j] == 'Z' && tiao[j])) + { obj = j; break; } + } + } + } + if (obj != -1) + { + pos = i; + F_target = obj; // 保存目标 + break; + } + } + // 跳过 J(无懈可击不能主动使用) + } + if (pos == -1) break; + + char card = p[now][pos]; + p[now][pos] = 0; + + if (card == 'P') + { + stre[now]++; + } + else if (card == 'Z') + { + zgln[now] = true; + } + else if (card == 'N') + { + NW(now, 'K'); + if (pd()) break; + } + else if (card == 'W') + { + NW(now, 'D'); + if (pd()) break; + } + else if (card == 'K') + { + do_K(now, nex[now]); + usedK = true; + if (pd()) break; + } + else if (card == 'F') + { + if (F_target != -1 && stre[F_target] > 0) + { + do_F(now, F_target); + if (pd()) break; + } + F_target = -1; + } + } +} + +int main() +{ + init(); + for (int i = 0; pd() == 0; i = nex[i]) + { + if (stre[i] <= 0) continue; + mp(i, 2); + cp(i); + } + printf("%s\n", pd() == 1 ? "MP" : "FP"); + for (int i = 0; i < n; ++i) + { + if (stre[i] <= 0) + printf("DEAD\n"); + else + { + bool first = true; + for (int j = l[i]; j <= r[i]; ++j) + if (p[i][j] != 0) + { + if (!first) printf(" "); + printf("%c", p[i][j]); + first = false; + } + printf("\n"); + } + } + return 0; +} \ No newline at end of file