首页 > 代码库 > HDU 4887 Endless Punishment (矩阵离散对数)

HDU 4887 Endless Punishment (矩阵离散对数)

题意: 给你两个长度为n(n <= 31)的01序列A, B,问A序列最少改变多少次能变成B序列。序列的一次改变是这样的,首先有两个集合S1、S2,每个集合中表示的都是下标,如果集合S1中1的个数是奇数个,那么把序列的第一个数去掉,然后在尾部加上一个数1,偶数个的话则是加上一个数0,然后将S2集合对应的位置异或一下,这就是改变了一次。

思路:由于n<=31,即可知总的不同序列个数是2^n。对于一个序列的一次改变,可以构造个转移矩阵,那么改变一次其实就是乘一次这个矩阵,设初始矩阵是A, 转移矩阵是B, 目标矩阵是C,问题就转换成求A * B^x = C (矩阵里的元素都是mod 2的)。纳尼,这不是就是在求离散对数嘛!只不过是矩阵的离散对数。那么问题就简单了,还是和求普通的离散对数一样。

普通的离散对数 http://blog.csdn.net/jayye1994/article/details/11961635

矩阵离散对数的话,由于总状态数只有2^31,x不会超过总状态数,假设tot是总状态数,定义m = sqrt(tot) + 1,先处理出C * B^i  (0 <= i < m),对于每个i得到的矩阵的状态放入map中,值为i,然后枚举计算 A * B^( i*m ) (1 <= i <= m),一旦得到的状态在map里,说明找到了答案,答案即为 i*m - map(状态),这个想一下就明白的,注意初始和目标状态相同时先特判下,然后注意计算的时候不能整个矩阵相乘,整个矩阵相乘复杂度是O(n^3),由于保存的矩阵只有第一行是有效的,所以复杂度可以转化成O(n^2),这样就不会超时了。



code:

<script src="https://code.csdn.net/snippets/441691.js" type="text/javascript"></script>