题目
T(T<=5e5)组样例,
Alice和Bob在一个3*3的方格上玩取石子,9个格子每个格子对应一堆石子,
第i行第j列现有石子数为aij(1<=aij<=1e9),
Alice先手,Alice第一步必须将一堆石子全取走,Bob第一步也必须将一堆石子全取走,
之后的操作中,Alice和Bob正常像Nim一样取石子,
如果X取完石子后,出现了同一行三堆都没有石子或同一列三堆都没有石子的局面,则X胜
问Alice第一步有多少种选堆策略,可以保证后续必胜
思路来源
官方题解
题解
赛中没看到两人第一步都要全取
由于题目的nim性质,可以行与行、列与列互换,不影响答案,
不妨设Alice第一步完全取走(1,1),
这样,Bob第一步就不能与之同行同列,只能在(2,2)(2,3)(3,2)(3,3)里取,
不妨设Bob第一步完全取走(2,2),
这样在后续的操作中,对于(1,2)(1,3)(2,1)(2,3)(3,1)(3,2),两人谁先取到这六堆的最后一颗石子谁输
即对这6堆,每一堆减去一颗石子后,再考虑上(3,3)这一堆,
七堆石子谁先取完谁获胜,因为另一方只能被迫去取六堆的最后一颗石子,
如果对于Alice的(1,1),Bob(2,2)(2,3)(3,2)(3,3)四种局面都是Bob负,则Alice必胜,
统计个数即可,代码统计的是Alice不能必胜的堆数non
由于T=5e5,所以要枚举的精准一点,不能9*9*9的for
代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
#define fi first
#define se second
typedef unsigned long long ull;
int t,a[4][4],c,non;
P now[15];
int main(){
scanf("%d",&t);
while(t--){
non=0;
c=0;
for(int i=1;i<=3;++i){
for(int j=1;j<=3;++j){
scanf("%d",&a[i][j]);
now[++c]=P(i,j);
}
}
for(int i=1;i<=c;++i){
for(int j=1;j<=c;++j){
if(i==j)continue;
if(now[i].fi==now[j].fi || now[i].se==now[j].se)continue;
int nim=0;
for(int k=1;k<=3;++k){
for(int l=1;l<=3;++l){
if(P(k,l)==now[i] || P(k,l)==now[j])continue;
if(k==now[i].fi || k==now[j].fi || l==now[i].se || l==now[j].se){
nim^=(a[k][l]-1);
}
else{
nim^=a[k][l];
}
}
}
//printf("(%d,%d) (%d,%d) nim:%d\n",now[i].fi,now[i].se,now[j].fi,now[j].se,nim);
if(nim==0){
non++;
break;
}
}
}
printf("%d\n",9-non);
}
return 0;
}