SG函數應用模板題,但還是想寫一下(SG入門從此起步)
大意是:有很多堆糖果,每個人可以在一堆取走任意多個糖果,或者將其分成3個非空堆。最後取走爲勝,問先手勝還是後手。
主要在用SG打表上,用SG輸出每個值的mex,從中找規律。
#include <bits/stdc++.h>
#define maxn 1000
using namespace std;
///題目中要求的是可以分解爲三堆,或者可以取走任意個
int sg[maxn];
bool vis[maxn];
int makesg(int num)
{
if(sg[num]!=-1)
return sg[num];
memset(vis,0,sizeof(vis));
for(int i=1;i<num;i++)///sg的值小於num的值
{
int a=makesg(i);
for(int j=1;j<num-i;j++)
{
int b=num-i-j;///根據題目要求將一堆分成三堆
int c=makesg(j);
int d=makesg(b);
int sgg=a^d^c;
vis[sgg]=1;///這個子狀態已經找過了
}
vis[a]=1;
}
vis[0]=1;
for(int i=1;;i++)
{
if(!vis[i]) return i;///一直未出現的即是mes{}中未出現的最小的非負整數
}
}
int main()
{
memset(sg,-1,sizeof(sg));
for(int i=1;i<=100;i++)
{
sg[i]=makesg(i);
}
for(int i=1;i<=100;i++)
{
printf("sg[%d]=%d\n",i,sg[i]);
}
}
通過打表可知:8的倍數和7的倍數的SG值會互換,其他的SG值和本值相同,故AC代碼如下:
#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
typedef long long ll;
ll T;
ll x;
ll N;
ll sg(ll x)
{
if(x%8==0)return x-1;
if(x%8==7)return x+1;
return x;
}
int main()
{
scanf("%I64d",&T);
while(T--)
{
scanf("%I64d",&N);
ll ans=0;
for(int i=0;i<N;i++)
{
scanf("%I64d",&x);
ans^=sg(x);
}
if(ans)printf("First player wins.\n");
else printf("Second player wins.\n");
}
return 0;
}