http://codeforces.com/problemset/problem/1312/F
题意:
给出n个数,有3种攻击方式,分别是选择一个正数减去x,y,z
(
)。
对于一个数,第2种和第三种攻击不能对其连续实施。(上次使用第二种攻击的这个数,下次攻击这个数就不能用第二种)
两个人的game。谁攻击完后所有数变为0谁获胜。问先手有多少第一步的下法,使得自己必胜。(不同数或者不同攻击算不同的走法)
解析:
不能连续使用的限制固定在每个数自身上,所以可以进行单独游戏SG计算再异或。
考虑单个游戏的SG计算。
对于状态数特别大的SG计算,有两种想法:打表找规律,找循环节。这里显然是后者。因为变化不多,只有3种,所以SG值 。并且每次 。
单个状态无非是SG[i][j]表示值为i上次攻击为j。然后将 这15个状态塞进map,找到循环节。
最后,对每个数尝试每种攻击之后的状态,判断是不是0(对对面必输态)。
代码:
/*
* Author : Jk_Chen
* Date : 2020-03-25-13.55.54
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=3e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
int n,val[3];
LL a[maxn];
void Input(){
n=rd;rep(i,0,2)val[i]=rd;
rep(i,1,n)a[i]=rd;
}
typedef vector<vector<int>> node;
int SG[maxn][3];
bool vis[5];
map<node,int>ID;
int base,period;
void Begin(){
node O(5,vector<int>(3,0));
ID[O]=0;
int p=1;
while(1){
rep(i,0,2){
mmm(vis,0);
rep(j,0,2){
if(i&&j==i)continue;
int x=max(0,p-val[j]);
vis[SG[x][j]]=1;
}
int j=0;
while(vis[j])j++;
SG[p][i]=j;
}
node T(5);
rep(i,0,3)T[i]=O[i+1];
rep(i,0,2)T[4].pb(SG[p][i]);
if(ID.count(T)){
period=p-ID[T];
base=p;
return;
}
ID[T]=p;
O=T;
p++;
}
}
LL getSG(LL p,int j){
if(p<=base)return SG[p][j];
LL len=(p-base+period-1)/period;
p-=len*period;
return SG[p][j];
}
void Deal(){
int Sg=0;
rep(i,1,n){
Sg^=getSG(a[i],0);
}
int ans=0;
rep(i,1,n){
Sg^=getSG(a[i],0);
rep(j,0,2){
LL x=max(0ll,a[i]-val[j]);
if(!(Sg^getSG(x,j)))
ans++;
}
Sg^=getSG(a[i],0);
}
printf("%d\n",ans);
}
void Init(){
ID.clear();
}
int main(){
int t=rd;
while(t--){
Init();
Input();
Begin();
Deal();
}
return 0;
}
/*_________________________________________________________end*/