现在有一排挨着放的格子,这一排是无限长,某些格子里面放了一些棋子,现在可以有两个操作:
1.拿出一个格子里的一颗棋子,在其左边的两个格子里分别放入一个棋子;
2.如果两个连续的格子都有棋子,可以从这两个格子分别拿出一个棋子,然后在两个格子的右边这个格子放入一颗棋子;
可见这两个操作是互逆的。
现在的任务是:给定一个初始的格子状态,有些格子有棋子,有些格子空着,希望通过上述两种操作,将这个格子带转换为:
1.每个格子最多只有一颗棋子;
2.不能有连续的格子都有棋子;
当然给定的初始序列可以有很多种终止状态,求出任意一种即可。
一个直观暴力的方法是将所有大于1个格子变成1,即将多余的棋子全通过操作1放到左边去,相当于向左压平,然后通过操作2向延伸;
这个操作一定是会终止的,因为给定初始格子状态后,操作1一定是有限的,而操作2每次会将棋子数量减少1,所以最终一定会停止;
我想介绍的是另一个非常Geek的方法,也是守恒思想的应用。
首先我们看操作1和2,假设4号格子(因为是无限长,所以几号几号都是人为给定一个开始基准设定的)和5号格子各有一颗棋子,那么通过操作2,可以得到6号格子的一颗棋子;
即 4 A+ 5 A = 6 A , A是随意的一个标记,可以理解为有棋子这个情况。
所以,如果我们能给每个格子赋以一个权值,最后是不是能得到点什么呢?
假设第i个格子的权值为 Fi ,那么必有 Fi = F i-1 + F i-2 , 看到这个递推式是不是很眼熟呢,那就是神奇的Fibonacci数列,是不是感到数学很神奇呢?
所以当我们给带子上的所有格子根据Fibonacci数列赋好权值之后,当前给定状态的所有棋子的权值累加和就可以算出来了:
Sum = Fi * Ai 累加。对吧,而可知我们的操作是守恒的,因此最后的状态的Sum一定也是相等的~
因此既然我们知道这个Sum了,我们就可以直接来构造一个符合这个Sum的最后状态了,根本不在乎中间是怎么转换的。
也就是我们 有一个Sum,要将他分解到Fibonacci数列中某些不相邻项的和~
这个使用贪心就好了,每次取离剩余Sum最近的那个Fibonacci数,然后标记对应的格子放1,直到Sum=0;