[Nim] SRM 304 div1 TheXGame

翻译题解

首先给出结论 把一段看做一堆石子 可以做到跟nim游戏等价

具体 我们需要归纳证明一个结论

当前current_multiplier为 c ,石子总数为 n ,若异或和为 0 那么后手将以至少 n2c 的净得分获胜

  • 当游戏只剩最后两步的时候,两堆石子分别是 n2 ,那么后手会赢 n2c×2n2c=n2c
  • 否则我们设先手拿掉之后还剩 y 个石子,后手接着拿 x 个石子,并保持异或和仍为 0 ,那么之后根据归纳的结论,之后会赢 yx2c×4,这两步先手得 (ny)c ,后手得 xc×2 分,那么总共后手得 3ycnc ,跟 x 无关了,那么先手肯定会拿最多,让 y 小,因为异或和为 0 ,那么最多一堆是n2,也就是说,后手至少会赢 n2c ,得证

还缺关键的一步,后手是不是一定存在决策,使得异或和仍然不变

考虑nim游戏,先手从一堆中拿去了一些,后手必然从另一堆拿,因为后手再从这堆拿不可能满足 那么如果先手把一堆 a 分裂 b+c<a,那么可以相当于拿走了 ab xor c 个石子 因为 b xor cb+ca ,仿照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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值