首先给出结论 把一段看做一堆石子 可以做到跟nim游戏等价
具体 我们需要归纳证明一个结论
当前current_multiplier为 c ,石子总数为
n ,若异或和为 0 那么后手将以至少n2c 的净得分获胜
- 当游戏只剩最后两步的时候,两堆石子分别是 n2 ,那么后手会赢 n2c×2−n2c=n2c
- 否则我们设先手拿掉之后还剩
y
个石子,后手接着拿
x 个石子,并保持异或和仍为 0 ,那么之后根据归纳的结论,之后会赢y−x2c×4 ,这两步先手得 (n−y)c ,后手得 xc×2 分,那么总共后手得 3yc−nc ,跟 x 无关了,那么先手肯定会拿最多,让y 小,因为异或和为 0 ,那么最多一堆是n2 ,也就是说,后手至少会赢 n2c ,得证
还缺关键的一步,后手是不是一定存在决策,使得异或和仍然不变
考虑nim游戏,先手从一堆中拿去了一些,后手必然从另一堆拿,因为后手再从这堆拿不可能满足 那么如果先手把一堆 a 分裂
b+c<a ,那么可以相当于拿走了 a−b xor c 个石子 因为 b xor c≤b+c≤a ,仿照nim从别的堆拿掉就好了
然后只要枚举第一次的操作就好了
还有一个特判 如果把唯一的一整堆都拿了,那么还是不能胜的
// BEGIN CUT HERE
#include<conio.h>
#include<sstream>
// END CUT HERE
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<string>
#include<set>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int N=55;
int len,n,a[N];
class TheXGame{
public:
int firstMove(string B){
len=B.length(); n=0;
for (int i=0,j;i<len;)
if (B[i]=='-'){
j=i; while (j+1<len && B[j+1]=='-') j++;
a[++n]=j-i+1; i=j+1;
}else
i++;
int sum=0;
for (int i=1;i<=n;i++) sum^=a[i];
int ans=1<<30;
for (int i=1;i<=n;i++)
for (int j=0;j<=a[i];j++)
for (int k=0;k<=a[i];k++)
if (!(n==1 && j==0 && k==0))
if (j+k<a[i] && (sum^a[i]^j^k)==0)
ans=min(ans,a[i]-j-k);
return ans==1<<30?-1:ans;
}
// BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); }
private:
template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { string Arg0 = "X---X-X-"; int Arg1 = 1; verify_case(0, Arg1, firstMove(Arg0)); }
void test_case_1() { string Arg0 = "----"; int Arg1 = 2; verify_case(1, Arg1, firstMove(Arg0)); }
void test_case_2() { string Arg0 = "--XXX" ; int Arg1 = -1; verify_case(2, Arg1, firstMove(Arg0)); }
void test_case_3() { string Arg0 = "--------X-----X----X"; int Arg1 = 3; verify_case(3, Arg1, firstMove(Arg0)); }
// END CUT HERE
};
// BEGIN CUT HERE
int main(){
TheXGame ___test;
___test.run_test(-1);
getch() ;
return 0;
}
// END CUT HERE