一开始看看感觉还可以用【科学的】二维SG,一看数据,10000位,exm?
于是我先写了个SG函数,敲进去几个数据
啊我好像看到规律了!—> AC
嘛这样打表是不行的,我们还是看个正解吧
当游戏状态属于前者时,Matrix67可以把糖果数被5除余1、4或正好除尽的那一堆分成糖果数被5除余数都是2或3的两堆(他总能做到这一点)
而对方不得不把其中一堆糖果又分出新的糖果数被5除余1、4或正好除尽的一堆留给Matrix67操作。
这样逼着对方总是面临必败的状态,使得最后对方不得不把2个糖果或者3个糖果分成两堆,
从而使Matrix67赢得游戏。
反过来,当Matrix67面临两堆糖果的数目被5除余数都是2或3的状态时,Shadow总可以取胜。
所以就是如果两堆的个数的个位数都是2 3 7 8的一个的话
就是Shadow取胜,不然就是Matrix
暴力【表】
#include
#include
#include
using namespace std;
int sg[1005][1005],n,m;
int get_sg(int x,int y)
{
if (x>y) swap(x,y);
if (sg[x][y]!=-1) return sg[x][y];
if (x==1 || y==1) {sg[x][y]=1; return 1;}
bool ext[1005];memset(ext,0,sizeof(ext));
for (int i=1;i+i<=y;i++)
ext[get_sg(i,y-i)]=1;
for (int i=1;i+i<=x;i++)
ext[get_sg(i,x-i)]=1;
for (int i=0;;i++)
if (!ext[i]){sg[x][y]=i;break;}
return sg[x][y];
}
int main()
{
memset(sg,-1,sizeof(sg));
while (1)
{
scanf("%d%d",&n,&m);
if (get_sg(n,m)) printf("先手\n");else printf("后手\n");
}
}
AC
#include
#include
using namespace std;
char x[10005],y[10005];
int main()
{
for (int i=1;i<=10;i++)
{
scanf("%s%s",x,y);
int l1=strlen(x)-1,l2=strlen(y)-1;
if ((x[l1]=='2'||x[l1]=='3'||x[l1]=='7'||x[l1]=='8')&&(y[l2]=='2'||y[l2]=='3'||y[l2]=='7'||y[l2]=='8'))
printf("Shadow\n");else printf("Matrix67\n");
}
}
首先想到打表,但这什么鬼啊我不会啊!那就硬找规律?
容易发现
[1,9]Stan
[10,18]Ollie
[19,162]Stan
…
我们可以这样极限考虑,要是Stan知道ta会赢,那每回合会选最大的9,Ollie知道自己乘上也没什么用,给ta个最小的2,然后Stan选个9就能达到自己的目标,Ollie要是赢的话是同样的
然后你随便试试19-162之间的数就发现Ollie总是不能赢,就可以发现规律了
1~9*1 Stan
9*1+1~9*2 Ollie
9*2+1~9*2*9 Stan
那么我们往下推测
9*2*9+1~9*2*9*2 Ollie
规律get?
其实还有一个问题是这个数字很大,但是可以用double读入
#include
#include
using namespace std;
double n;
int main()
{
while (~scanf("%lf",&n))
{
while (1)
{
if (n<=9) {printf("Stan wins.\n");break;}
if (n<=18) {printf("Ollie wins.\n");break;}
n/=18;
}
}
}
Alice和Bob轮流取石子,每一次可以从任意一堆中拿走任意个石子,也可以将一堆石子分为两个小堆。先拿完者获胜。
这个问题可以用SG函数来解决。首先,操作①其实和Nim游戏没什么区别,对于一个石子数为k的点来说,后继可以为0…k-1。而操作②实际上是把一个游戏分成了两个游戏。根据游戏的和的概念,这两个游戏的和应该为两个子游戏的SG函数值的异或。
比如说,状态3的后继有:0、1、2、(1,2),他们的SG值分别为0、1、2、3,所以sg(3) = 4
但是一看数据范围2^31 - 1。。。然后打了个表,规律get?
#include
#include
using namespace std;
int sg[10005];
int get_sg(int x)
{
if (sg[x]!=-1) return sg[x];
bool ext[10005];memset(ext,0,sizeof(ext));
for (int i=x-1;i>=0;i--)
ext[get_sg(i)]=1;
for (int i=1;i+i<=x;i++)
ext[get_sg(i)^get_sg(x-i)]=1;
for (int i=0;;i++)
if (!ext[i]) {sg[x]=i; break;}
return sg[x];
}
int find_sg(int x)
{
if (x%4==3) return x+1;
if (x%4==0) return x-1;
return x;
}
int main()
{
//表
/* memset(sg,-1,sizeof(sg)); for (int i=1;i<=50;i++) printf("sg[%d]=%d\n",i,get_sg(i));*/
int T,n;
scanf("%d",&T);
while (T--)
{
int k=0,a;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a);
k^=find_sg(a);
}
if (k) printf("Alice\n");else printf("Bob\n");
}
}
这题什么鬼啊,我为什么连暴力都不会啊?
然后画了几个格子试一试,发现早晚他们都会把整个棋盘走一遍,那不就是看这个棋盘格子的奇偶吗。。
再退一步,这不就是看行数的奇偶吗。。
AC。
#include
using namespace std;
int main()
{
int n;
while (scanf("%d",&n) && n)
{
if (n%2) printf("Bob\n");
else printf("Alice\n");
}
}