题目:
题解:
一看到是博弈就吓住了,害怕是什么SG乱搞。然而这道题目并不要什么SG函数
我们发现所有的状态只有2n个点,即Alice/Bob先手,棋子在第i个位置。那么显然棋子在1的两个状态都是必败态
然后是个博弈常用的结论:
如果一个状态可以转移到任何一个必败态,则这个状态是必胜态
如果一个状态只能转移到必胜态,则这个状态是必败态
那么我们可以根据这个从1开始暴力标记,当一个节点是必败态的时候,我们把ta所有的前驱标为必胜态
当一个节点是必胜态的时候,我们把ta所有的前驱出度–,当减到0的时候就是必败态啦
代码:
#include <queue>
#include <cstdio>
using namespace std;
const int N=7005;
int a[N],b[N],end[N*2],du[N*2];bool vis[N*2];
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
int n;scanf("%d",&n);
scanf("%d",&a[0]);
for (int i=1;i<=a[0];i++) scanf("%d",&a[i]);
scanf("%d",&b[0]);
for (int i=1;i<=b[0];i++) scanf("%d",&b[i]);
end[0]=end[n]=-1;vis[0]=vis[n]=1;
queue<int>q;q.push(0);q.push(n);
while (!q.empty())
{
int now=q.front(); q.pop();
if (now>=n)//b
{
for (int i=1;i<=a[0];i++)
{
int pre=(now-a[i])%n;
if (vis[pre]) continue;
if (end[now]==-1) vis[pre]=1,end[pre]=1,q.push(pre);
else if (++du[pre]==a[0]) vis[pre]=1,end[pre]=-1,q.push(pre);
}
}
else
{
for (int i=1;i<=b[0];i++)
{
int pre=(now-b[i]+n)%n+n;
if (vis[pre]) continue;
if (end[now]==-1) vis[pre]=1,end[pre]=1,q.push(pre);
else if (++du[pre]==b[0]) vis[pre]=1,end[pre]=-1,q.push(pre);
}
}
}
for (int i=1;i<n;i++)
if (end[i]==1) printf("Win ");
else if (end[i]==-1) printf("Lose ");
else printf("Loop ");
printf("\n");
for (int i=1;i<n;i++)
if (end[i+n]==1) printf("Win ");
else if (end[i+n]==-1) printf("Lose ");
else printf("Loop ");
}