P9753 消消乐题解
不知道算不算题解。
大概是一些零散的想法。
首先一个观察就是,用栈从左侧往右扫描。然后你发现栈内元素一样说明这两个点的区间就是可以消除的。
因此你可以对栈哈希。哈希可以直接考虑数组哈希的做法,对于第 push 就是栈顶的值加上当前值乘上
不过,这个东西还是太难发现了。
我们不妨换个角度。
简而言之,你从左往右做操作,相邻两个操作抵消。这意味着
如果你熟悉线性代数,很快就会发现这可以是一个镜面反射。因此我们可以用一个镜面反射的矩阵代替每个字符
此外这还依赖一个性质就是结合律。假设有
这也是我们可以使用矩阵的原因,有结合律,但是我们需要消除交换。
此外还有一个满足条件的哈希,那就是对换。你可以使用对换来代表每个元素。你只需要
维护这个东西的做法是直接维护整个置换,然后对置换做数组哈希。
对于,
或者采用比较笨的办法,用
总结一下就是,哈希的作用是快速判等(这里的等指的是等价关系,并非狭义的相等),前提是可以设计哈希函数使得同一个等价类的哈希值相同。
此外顺手记录一下之前听到另一个有趣的应用,就是校验码。考察银行卡号,在卡号最后增加一位,使得可以检验银行卡号是否合法,减少转账录错银行卡号转给了错误的人这种事情发生的概率。
其似乎仍然是把所有银行卡划分成若干等价类,选择一个等价类,称这个等价类是合法的银行卡号。一个简单方法就是在最后加上一位作为校验码。
请注意我们此时的要求。不满足交换律,可以有结合律(因为字符串拼接有结合律)。并且要能检测某一位出错的情况,且校验码要在
最后一个要求让直接字符串哈希不太可能了。一个有趣的解法是,将
似乎有一个人设计了将
不过似乎并没有银行采取这种方法。
此外还有集合哈希。集合哈希更好的做法其实并不是直接对 01 字符串做哈希,此类哈希函数很难写,并且缺乏良好的性质。我们有着更好的哈希方式。考虑给每个元素随机权值,定义集合的哈希值就是所有元素乘积相乘。
这样做的更好的方法是可以很好的对集合族做哈希,定义集合族的哈希为所有集合的哈希相加。如果要给一个集合族所有个数添加一个元素,那么只需要哈希值乘上一个数即可。
这个做法的本质就是若干