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*/