7.18

博弈论dp

还是合并石子那道题,我们现在可以合并任意两堆,但是合并两堆的代价是它们的异或和,求合并成一堆的最小代价

N≤16

看起来像个状压dp

f[s]表示合并s状态的石子用的最小代价

s可以由s的子集推过来

判断子集:s&a=a,或者s|a=s,则a为s子集

复杂度:O(4n)

我们发现他过不了,太慢了

那怎么优化?

我们发现第二层的循环枚举了很多不是s的子集的情况

所以我们直接只枚举s的子集

 

 为什么这么写???

举个栗子:当前的s是1 0 1 0 1(代表4,2,0)

那么s-1=1 0 1 0 0,(s-1)^&s=1 0 1 0 0(代表4,2)

s-1-1:1 0 0 1 1 ,和s进行&操作后:1 0 0 0 1(代表4,0)

再减1:

优化之后就是O(3n)辣

 

博弈论dp正式开始

特征:

1.有一个游戏,玩家一定是A和B

2.是个回合制的游戏

3.这个游戏没有平局

4.胜负区分方法:当某个人无法进行操作的时候就输了

(fgo?战舰少女R?刀剑乱舞?)(算了算了非酋玩不了)(玄不救非氪不改命qwq)

 

 把游戏状态抽象成一张图

没有出边的点就代表无法进行下一步,所以是必败态。

能够走到必败态的点就是必胜态(因为必败态是对手操作)

那左上角的点呢?

这里就会有一个限制,A,B都绝顶聪明,会选择最优策略,所以左上角的点是必胜态

f[s]=true/flase表示是否是必胜态

即它的转移状态中有一个是必败态,则它是必胜态,若所有都是必胜态,则它是必败态

回到这个题

f[i][j]表示s当前还剩下i,对手上一轮减了j,是必胜还是必败

转移:枚举r,1≤r≤j*k

代码用记忆化搜索

第二类:

现在有两个强者A,B有N个游戏,同时玩

例如A可以在G1里面操作,B可以去G2里面操作

其他设定不变

输的条件是在每个游戏里面都无法移动

(立体五子棋?)(手动滑稽)

 

简单(雾)的例子:取石子游戏:

有n堆石子,第i堆石子的数量是ai,A先手,玩家可以从某一堆石子里面取走任意数量的石子(可以把这一堆取完),当没有办法取石子的时候就输了,也就是当一个人把石子变成0的时候,下一个操作的人会输

f[b1][b2]....[bn]:表示当前第i堆有bi个石子

转移:枚举从哪一堆石子中拿出多少个(貌似有点诡异)

这种方法除了炸了之外很完美

 

对于n个游戏,我们有SG函数

考虑只有一堆石子,先手必胜

0是必败态,所以sg[0]=0

找出i能转移到的所有状态,把这些状态的sg函数写出来,找出最小的没有出现的自然数,就是sg[i]   //通顺emm

所以sg[1]=0.sg[2]=2(1可以转移到0,2可以转移到1,0)

我们发现这个题里的sg[i]=i

在这个题里我们可以手算出来所有的sg

 举个栗子

为什么红点的sg为0?

因为红点能够直接到达的点的sg是1,没有出现过的最小的自然数是0

sg=0,则先手必败

在这个题里面,ai的sg就是ai

那n个游戏的sg值怎么计算?

sg定理:n个游戏的sg值就是n个游戏的sg值异或起来

所以这里n个游戏的sg值就是a1^a2^a3^.............^an

如果sg值是0,先手必败

代码:

 

 现在有N堆石子a1,a2,a3...an,可以从一堆石子里面取走1~4个石子,问先手必胜还是必败

sg[0]=0

sg[1]=1

sg[2]=2

sg[3]=3

sg[4]=4

sg[5]=0(因为5可以转移到4,3,2,1)

sg[6]=1(转移到5,4,3,2)

所以sg[ai]=ai%5

所以这个题就是(a1%5)^(a2%5)^.............^(an%5)

一般方法:手算sg值,找规律,把每个的sg值异或起来,看是否为0

这个题里面,石子堆和石子堆有关系了

一般思路:把问题转化为取石子1.0的形式

把所有石子数是奇数的堆的下标取出来进行异或,看是否为0

为什么?

每次操作的两堆只有下面两种情况:

(下面用1表示奇数的堆,0表示偶数的堆)

     i     j                                        i    j

1. 0   1  ------------------------------>1  0

2.1    1------------------------------->0   0

我们把红色的0看做是两个1,那么我们的操作就是一直把右边的1往左移

我们就把石子堆的值看成石子堆的数量,下标看成值,然后就转换成了1.0版本

 把所有下标为奇数的石子数量异或起来

why?如果能把偶数位置搬到奇数位置,那就一定能把奇数位置搬到偶数位置,那偶数位置的石子好像没有什么用

所以就把下标为奇数的石子异或起来

每个格子到右下角的曼哈顿距离是不变的,如果我们能把偶数距离的石头移动到奇数距离的格子,那一定能从奇数距离的格子移动到偶数距离的格子,所以这个题和上题是一样的,只需要把奇数距离格子里的数异或起来就行了

显然这是只有一个游戏的问题

状压f[i]表示I状态的格子被标记了?

22000存不下qwq

所以我们考虑把它拆成多个游戏

我们发现在中间染色之后,左边两个格,右边两个格都不能染色了

 sg[i]表示长度为I的横条的sg值

在上面这个条里面,答案就是sg[3]^sg[4]

代码求sg值

 

 

 f[x][y]-------->f[1][x+y]

        ---------->f[2x][y]

       ----------->f[3x][y]

如果y>=n就是必败态,看谁能走到必败态,谁就是必胜态

N是30000,开个30000*30000的二维数组,几个G就存下了对吧qwq

好吧我们来谈正经的优化

我们发现第一维不可能取到不是2的倍数或不是3的倍数的数

所以f[a][b][y]表示现在是2a*3b是当前的x,

posted @ 2019-07-18 20:08  千载煜  阅读(220)  评论(0编辑  收藏  举报