【BZOJ2940】[POI2000] 条纹(Multi-SG)
大致题意: 有一堆石子,每次可以取\(a\)或\(b\)或\(c\)个石子,并把剩下的石子分成两部分。每次询问给定石子数目\(n\),问先手是否有必胜策略。
\(Multi-SG\)
听起来很高级的东西,其实也就一般般啦。
放在这题中,我们和普通题目一样定义\(SG\)函数,假设当前有完整一堆\(i\)个石子,考虑其后继状态。
我们枚举取几个石子(\(a\)或\(b\)或\(c\)),然后枚举怎么分,就得出了所有后继状态。
则\(SG(i)\)的值就等于:
\[mex\{SG(j)\ xor\ SG(i-j-a),SG(j)\ xor\ SG(i-j-b),SG(j)\ xor\ SG(i-j-c)\}
\]
因为\(a,b,c\)是一开始就给定的,因此我们完全可以预处理。
最后只要对于每个询问的\(n\)判断\(SG(n)\)是否为\(0\)即可。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
using namespace std;
int n,a,b,c,SG[N+5],vis[N+5];
int main()
{
RI Tt,i,j;for(scanf("%d%d%d",&a,&b,&c),i=1;i<=N;++i)//预处理i的SG值
{
for(j=0;j+a<=i;++j) vis[SG[j]^SG[i-j-a]]=i;//取a个石头
for(j=0;j+b<=i;++j) vis[SG[j]^SG[i-j-b]]=i;//取b个石头
for(j=0;j+c<=i;++j) vis[SG[j]^SG[i-j-c]]=i;//取c个石头
for(j=0;vis[j]==i;++j);SG[i]=j;//SG值
}
scanf("%d",&Tt);W(Tt--) scanf("%d",&n),puts(SG[n]?"1":"2");return 0;//直接判断
}
待到再迷茫时回头望,所有脚印会发出光芒