P17128 [ICPC 2025 Shanghai R] AGI 题解

· · 题解

感谢 wyyinput 提供的 HACK 现已修改。

题意

2n 个数,Menji 先手,每回合选一个数 x,把 S 异或上 x 然后删掉这个数。Bot 后手,每回合删一个数但不影响 S。两人轮流,直到数全部删完。如果最终

## 思路 这道题的核心是搞清楚 Menji 的选数对最终结果的影响,以及 Bot 的删数能不能干扰。 先把所有数按数值分组,统计每种数出现的次数。出现偶数次的数,无论 Menji 选不选到它们,最终异或起来都会被抵消掉(因为异或偶数个相同数等于 $0$)。真正决定最终 $S$ 的,**只有那些出现次数为奇数的数**。 我们可以设出现奇数次的数值种类数为 $e$。 - 如果 $e$ 是奇数,那么这些数两两配对后还会剩下一个落单的,最终 $S$ 一定非零,Menji 无论如何都赢不了,Bot 赢。 - 如果 $e$ 是偶数,Menji 可以通过策略保证自己选到的数恰好让异或和为 $0$。Bot 虽然能删数,但删不掉 Menji 已经选过的数,也改变不了奇偶性的格局,所以 Menji 能赢。 ::::warning[But] 特殊情况:$n = 1$ 时只有两个数,Menji 只能选一个,Bot 删另一个。如果两个数中有一个是 $0$,Menji 选 $0$,最终 $S = 0$,赢。 否则 $S$ 非零,输。 :::: 综上,做法也就简单明了了:**统计每种数的出现次数,数一下有多少种出现次数是奇数,然后按上面的规则判断。** ## 代码 ```cpp line-number #include<bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(0);cin.tie(0); int T;cin>>T; while(T--){ int n;cin>>n; unordered_map<int,int> cnt; cnt.reserve(2*n+5); for(int i=0;i<2*n;i++){ int x;cin>>x; cnt[x]++; } int odd=0,s=0; int o1=-1,o2=-1; for(auto &p:cnt){ int x=p.first,c=p.second; if(c&1){ odd++; if(o1==-1) o1=x; else o2=x; } int h=c/2; if(h&1) s ^= x; } if(odd>2){cout<<"Bot\n";continue;} if(odd==0){ if(s==0) cout<<"Menji\n"; else cout<<"Bot\n"; continue; } int ok=0; if(o1==s || o2==s) ok=1; if(ok) cout<<"Menji\n"; else cout<<"Bot\n"; } return 0; } ``` 还是很简单的,完结撒花!