上海计算机学会2026年5月月赛C++丙组T5 石头剪刀布
·
石头剪刀布
题目描述
石头剪刀布的游戏,每一轮可以出三种招数:石头、剪刀、布。给定一个整数 NNN,表示需要进行 NNN 轮游戏。若规定每一轮出招不能与上一轮重复,请统计有多少种不同的出招序列?由于答案可能很大,输出答案模 1,000,000,0071,000,000,0071,000,000,007 的余数。
输入格式
单个整数 NNN
输出格式
输出答案模 1,000,000,0071,000,000,0071,000,000,007 的余数。
数据范围
- 对于 30%30\%30% 的数据,1≤N≤101 \le N \le 101≤N≤10
- 对于 60%60\%60% 的数据,1≤N≤1,0001 \le N \le 1,0001≤N≤1,000
- 对于 100%100\%100% 的数据,1≤N≤1,000,000,0001 \le N \le 1,000,000,0001≤N≤1,000,000,000
样例数据
输入:
3
输出:
12
题解
我先来分析这道石头剪刀布的数学规律,再讲解代码思路。
一、题目分析
游戏有石头、剪刀、布共3种出法,规则是相邻两轮不能出一样的招数,求 N 轮的总出招序列数,结果对 109+710^9+7109+7 取模。
- 第 1 轮:没有上一轮限制,一共有 3 种选择。
- 从第 2 轮开始:每一轮都不能和上一轮相同,每轮都只有 2 种选择。
- 总方案数公式:ans=3×2N−1ans = 3 \times 2^{N-1}ans=3×2N−1。
题目中 NNN 最大到 10910^9109,普通循环会超时,所以我选择**快速幂(二分幂)**来高效计算 2N−12^{N-1}2N−1。
二、完整带注释代码
#include<bits/stdc++.h>
using namespace std;
// 模数 1e9+7
const int mod = 1e9+7;
int main() {
int n;
// 读入游戏轮数 n
cin>>n;
// 公式:3 * 2^(n-1),先把答案初始化为第一轮的3种选择
long long ans = 3;
// base底数,也就是每一轮可选的2种出法
long long m = 2;
// 计算指数 n-1,所以先让n自减1
n--;
// 快速幂核心循环,计算 m^n 并乘到 ans 上
while(n > 0){
// 如果当前二进制位为1,将当前底数乘入答案
if (n % 2){
ans *= m;
// 每次运算都取模,防止数据溢出
ans %= mod;
}
// 底数平方,二分降幂
m *= m;
m %= mod;
// 右移一位(等价于 n /= 2)
n /= 2;
}
// 输出最终结果
cout<<ans;
return 0;
}
三、思路总结
- 我先推导出数学公式:总方案数 = 3×2n−13 \times 2^{n-1}3×2n−1。
- 因为数据范围极大,nnn 可达 10910^9109,所以不能暴力循环乘 n−1n-1n−1 次,改用快速幂优化时间复杂度到 O(logn)O(\log n)O(logn)。
- 快速幂过程中,我全程对 109+710^9+7109+7 取模,避免长整型溢出,保证计算合法。
- 以样例输入
3举例:3×22=123 \times 2^{2} = 123×22=12,和样例输出一致,验证思路正确。
更多推荐
所有评论(0)