把五手势胜负关系预编译成查表,两人按各自周期取模逐轮判胜计分,O(N) 模拟出全部 N 轮得分。
OJ: roj
题目 ID: 3618
难度:入门
标签:入门模拟python
创建: 2026-10-02 10:54
更新: 2026-10-06 15:14
题目描述
甲、乙两人玩升级版石头剪刀布:手势
样例输入:10 5 6 / 0 1 2 3 4 / 0 3 4 2 1 0,输出 6 2。
思路
把
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 10:54
# update_at: 2026-10-02 10:54
import sys
# 五种手势:0 剪刀,1 石头,2 布,3 蜥蜴人,4 斯波克
# 胜负关系表:(先手, 后手) 表示先手胜后手,共 5 × 2 = 10 对
BEATS: set[tuple[int, int]] = {
(0, 2), (0, 3), # 剪刀胜布、蜥蜴人
(1, 0), (1, 3), # 石头胜剪刀、蜥蜴人
(2, 1), (2, 4), # 布胜石头、斯波克
(3, 2), (3, 4), # 蜥蜴人胜布、斯波克
(4, 0), (4, 1), # 斯波克胜剪刀、石头
}
def winner(hand_a: int, hand_b: int) -> int:
"""单轮判胜:甲胜返回 1,乙胜返回 -1,平局返回 0。"""
if (hand_a, hand_b) in BEATS:
return 1
if (hand_b, hand_a) in BEATS:
return -1
return 0
def tally(rounds: int, seq_a: list[int], seq_b: list[int]) -> tuple[int, int]:
"""打满 rounds 轮后返回 (甲得分, 乙得分),出拳按各自周期循环取。"""
score_a = score_b = 0
for r in range(rounds):
result = winner(seq_a[r % len(seq_a)], seq_b[r % len(seq_b)])
if result == 1:
score_a += 1
elif result == -1:
score_b += 1
return score_a, score_b
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
rounds = next(data) # 共进行 N 次猜拳
len_a = next(data) # 小 A 出拳周期长度
len_b = next(data) # 小 B 出拳周期长度
seq_a = [next(data) for _ in range(len_a)]
seq_b = [next(data) for _ in range(len_b)]
print(*tally(rounds, seq_a, seq_b))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 15:14
* update_at: 2026-10-06 15:14
*/
// main.cpp:升级版石头剪刀布,按各自周期出拳,逐轮判胜并累计得分。
#include <iostream>
typedef long long ll;
const int MAXN = 205;
// 胜负表:beats[i][j] 为 1 表示手势 i 胜手势 j。
// 手势编号:0 剪刀,1 石头,2 布,3 蜥蜴人,4 斯波克。
int beats[5][5];
int seq_a[MAXN]; // 小 A 的出拳周期
int seq_b[MAXN]; // 小 B 的出拳周期
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
// 五种手势各胜另外两种,共 10 对
beats[0][2] = 1; beats[0][3] = 1; // 剪刀胜布、蜥蜴人
beats[1][0] = 1; beats[1][3] = 1; // 石头胜剪刀、蜥蜴人
beats[2][1] = 1; beats[2][4] = 1; // 布胜石头、斯波克
beats[3][2] = 1; beats[3][4] = 1; // 蜥蜴人胜布、斯波克
beats[4][0] = 1; beats[4][1] = 1; // 斯波克胜剪刀、石头
ll n, len_a, len_b;
std::cin >> n >> len_a >> len_b;
for (ll i = 0; i < len_a; i++) {
std::cin >> seq_a[i];
}
for (ll i = 0; i < len_b; i++) {
std::cin >> seq_b[i];
}
ll score_a = 0;
ll score_b = 0;
for (ll r = 0; r < n; r++) {
int hand_a = seq_a[r % len_a]; // 第 r 轮小 A 的手势
int hand_b = seq_b[r % len_b]; // 第 r 轮小 B 的手势
if (beats[hand_a][hand_b]) {
score_a++;
} else if (beats[hand_b][hand_a]) {
score_b++;
}
}
std::cout << score_a << ' ' << score_b << std::endl;
return 0;
}