原题链接:
题面:
在桌面角色扮演游戏(TRPG,俗称“跑团”)中,玩家需要掷出若干个骰子,根据掷出的结果推进游戏进度。在线上同样可以跑团,方法是由玩家们向机器人发出指令,由机器人随机产生每个需要掷出的骰子的结果。
玩家向机器人发出的指令是一个仅涉及加法和减法的表达式,即对若干个数字进行一系列加法或减法计算。这些数字可以是直接给出的非负整数(数字不超过 1000),也可以是若干个骰子掷出的结果。
“掷骰子”这个动作对应的指令格式为 xdy,表示摇动 x 个 y 面的骰子(1≤x≤1000,2≤y≤1000)。当 x 为 1 时,1 可以省略。
例如指令
2d3+3-d4
的意思是:先掷出 2 个 3 面骰子(你不必考虑现实中是否存在这样的骰子),不妨假设结果为 1 和 3,则2d3
的结果就是两个骰子的面值之和 4;然后计算 4 + 3,得到结果为 7;再掷出 1 个 4 面骰子,不妨假设结果为 2,则计算 7 - 2 得到最终结果 5。本题就请你计算玩家输入的指令里,不同种类的骰子需要掷出几个,以及可能得到的结果在什么区间范围内。
解题思路:
根据题意进行模拟即可,由于只有加减法,所以我们不需要考虑算数优先级,每次计算最大值的时候,加法就假设骰子每个都最大,减法就假设每个骰子都最小,求最小值的时候则反之,注意给出的表达式里边还会有常量;实现方法是从左到右遍历一遍,每次遍历到下一个运算符的时候进行一次计算并且将下一个运算符记录下来。具体实现见代码。
代码(CPP):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e4 + 10;
const int INF = 0x3fffffff;
const int mod = 1000000007;
string s;
ll cnt[maxn];
void solve() {
cin >> s;
string tmp = "+";
int Max = 0, Min = 0;
for (int i = 0; i <= s.size(); i++) {
if (i == s.size() || s[i] == '+' || s[i] == '-') {
int x = 0, y = 0;
// 将x提取出来
int j;
for (j = 1; j < tmp.size(); j++) {
if (tmp[j] == 'd') {
break;
}
x = x * 10 + (tmp[j] - '0');
}
// 遍历停止位置不是'd',那么代表这是一个常量
if (tmp[j] != 'd') {
if (tmp[0] == '-') {
Max -= x;
Min -= x;
} else {
Max += x;
Min += x;
}
} else {
// 题目中说明了,表达式中的x可能被省略,省略则代表x为1
if (x == 0) { // 刚开始把这个条件判断写到了“提取x”代码段的后边,这样会导致x如果是常量0,则会被强行改为1
x = 1;
}
// 将y提取出来
for (j = j + 1; j < tmp.size(); j++) {
y = y * 10 + (tmp[j] - '0');
}
cnt[y] += x;
// Max Min
if (tmp[0] == '-') {
Max -= x;
Min -= x * y;
} else {
Max += x * y;
Min += x;
}
}
tmp = "";
}
if (i == s.size()) {
break;
}
tmp += s[i];
}
for (int i = 2; i <= 1010; i++) {
if (cnt[i]) {
cout << i << " " << cnt[i] << endl;
}
}
cout << Min << " " << Max << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << fixed;
cout.precision(18);
solve();
return 0;
}