利用 10 的倍数正好是必败局面这一性质,把超大整数按字符串读入并检查末位。
OJ: usaco
题目 ID: 1395
难度:入门
标签:博弈数学
日期: 2026-07-11 12:45
题意
有一堆
每次行动必须取走一个正整数回文数个石子。 如果轮到某头牛行动时没有石子可取,那么这头牛输。
给定若干个很大的
思路
暴力想法
小数据可以用博弈 DP。
设 win[s] 表示还剩 s 个石子时,当前行动者是否必胜。
如果存在一个回文数 p,满足 win[s-p] = false,那么 win[s] = true。
这个暴力适合小数据和对拍:
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-07-11 12:45
* update_at: 2026-07-11 12:46
*/
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
const int MAXS = 100000;
int t;
int query_value[20];
bool is_pal[MAXS + 5];
bool win_pos[MAXS + 5]; // win_pos[i] 表示还剩 i 个石子时先手是否必胜
bool check_pal(int x) {
string s = to_string(x);
int l = 0;
int r = (int)s.size() - 1;
while (l < r) {
if (s[l] != s[r]) {
return false;
}
l++;
r--;
}
return true;
}
void build_dp(int max_s) {
for (int i = 1; i <= max_s; i++) {
is_pal[i] = check_pal(i);
}
win_pos[0] = false;
for (int i = 1; i <= max_s; i++) {
win_pos[i] = false;
for (int take = 1; take <= i; take++) {
if (is_pal[take] && !win_pos[i - take]) {
win_pos[i] = true;
break;
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> t;
int max_s = 0;
for (int i = 1; i <= t; i++) {
string s;
cin >> s;
query_value[i] = stoi(s);
if (max_s < query_value[i]) {
max_s = query_value[i];
}
}
build_dp(max_s);
for (int i = 1; i <= t; i++) {
cout << (win_pos[query_value[i]] ? 'B' : 'E') << '\n';
}
return 0;
}但题目中的
关键性质
如果 d,其中 d 个石子,把剩余石子数变成
而任意正整数回文数都不可能是 0,回文要求首位也是 0,这会产生前导零,不合法。
所以:
text
10 的倍数:必败
不是 10 的倍数:必胜最终判断
由于
只看最后一个字符:
- 是
0,输出E; - 否则输出
B。
代码
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-07-11 12:45
* update_at: 2026-07-11 12:46
*/
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
string s;
cin >> s;
if (s[(int)s.size() - 1] == '0') {
cout << "E\n";
} else {
cout << "B\n";
}
}
return 0;
}复杂度
每组数据读入字符串需要
空间复杂度
总结
这题的关键是把取回文数的游戏转化成模
非