题解:P14688 [ICPC 2025 Yokohama R] Game of Names
:::info[解法一]{open}
神秘解法,我太菜了只能想到这。
超现实数法(Surreal Numbers):一种组合游戏的理论,将每个独立局面用一个数表示,正数表示先手优势,负数表示后手优势,零表示公平局面(在这里,平局时看谁先无法行动,判后手赢,即 Bob)。
calc 计算一段空白的超现实数值的 \(2\) 倍。
c 表示棋盘边界。
情况分析:
- 全空白棋盘;
- 左端是
a,右边到边界全是空白;(Alice 不能填第一个空白,Bob 可以填第一个空白,Bob 有优势) - 左端是
b,右边到边界全是空白;(Bob 不能填第一个空白,Alice 可以填第一个空白,Alice 有优势) - 左
a右b或左b右a;(公平段,双方机会均等) - 两端都是
a;(Alice 不能填任何空白,Bob 可以填所有空白,强烈对 Bob 有利) - 两端都是
b。(Bob 不能填任何空白,Alice 可以填所有空白,强烈对 Alice 有利)
#include<bits/stdc++.h>
#define int long long
using namespace std;
//return surreal number(*2)
//len==0 is impossible,use assert?
//here i just reurn 0
int calc(char l,char r,int len){
if(l>r) swap(l,r);
if(l=='c'&&r=='c')
return 0;
if(l=='a'&&r=='c'){
if(len==0) return 0;
if(len==1) return -2;
return -1;
}
if(l=='b'&&r=='c'){
if(len==0) return 0;
if(len==1) return 2;
return 1;
}
if(l=='a'&&r=='b')
return 0;
if(l=='a'&&r=='a'){
if(len==0) return 0;
return -2;
}
if(l=='b'&&r=='b'){
if(len==0) return 0;
return 2;
}
return 0;
}
void solve(){
int n;
string s;
cin>>n>>s;
int res=0;
char l='c';
int con=0;
for(int i=0;i<n;i++){
if(s[i]=='.'){
con++;
}else{
res+=calc(l,s[i],con);
con=0;
l=s[i];
}
}
if(l=='c'&&con==1){
cout<<"alice\n";
return;
}
res+=calc(l,'c',con);
if(res>0){
cout<<"alice\n";
}else if(res<0){
cout<<"bob\n";
}else{//the same means alice can't move
cout<<"bob\n";
}
return;
}
signed main(){
int T;
cin>>T;
while(T--)
solve();
return 0;
}
:::
:::info[官解]{open}
看了官解才发现我的解法有多招笑。
注:翻译自官方题解
名字游戏(Game of Names)
提案人:须美达也,作者:熊部宗,分析:须美达也。
设 \(mA\) 和 \(mB\) 分别为最初包含 Alice 和 Bob 名字的单元格数量,\(nA\) 和 \(nB\) 分别为它们最终的单元格数量。Alice的获胜条件是 $nA − mA > nB − mB $,即 \(nA − nB > mA − mB\)。
假设获胜者在比赛结果已定后仍继续在黑板上写下尽可能多的名字。考虑到棋盘的最终状态,我们可以看到,如果跳过空格,Alice 和 Bob 的名字必须交替出现(否则,其中一个人仍然可以在棋盘上写下自己的名字)。因此,\(nA −nB\) 由两端的格子决定如下(两端的格子总是被填满)。
- 若 Alice 同时选取两端格子,则其值为 \(1\)。
- 若 Bob 同时取用两端格子,则其值为 \(-1\)。
- 否则,该值为 \(0\)。
因此,游戏的胜负仅取决于哪位玩家占据两个端点单元格,该问题可通过适当的案例分析得以解决。
:::

浙公网安备 33010602011771号