Problem Description
给出 n 个 1 到 n 的数字 a1,a2,...,an 。m 组询问,每次询问给出一对整数 l,r。问 al,al+1,...,ar 是否是 1 到 (r-l+1) 的一个排列。
Input
多组测试样例,每组先给出 n 和 m;其后是 n 个数;再其后是 m 行,每行是一对整数 l,r。
Output
每组询问回答 YES
或者 NO
。
Solve1: prefix sum & rmq
我们把一个序列是一个排列这个条件看做要同时满足一下两点:
- 这个序列的和是要询问的排列的和
- 这个序列中元素两两不同。
第一点容易解决,我们可以使用前缀和数组。
第二点解决也不难。只要先预处理出 prei 表示在 i 之前最后一个与 ai 相等的数的位置(如果没有与之相等的位置那么设这个数是 0)。每次只要询问 (l, r) 内的 pre 的最大值,如果最大值小于 l ,说明命题成立;反之不成立。
于是第二点其实是一个 rmq 问题,遗憾的是 sparse table 在这个题目的限制内存下是不能用的。可以考虑线段树。
https://code.csdn.net/snippets/1582922/master/hdu5172.cpp/raw
Solve2: hash
hash 是一种比较时髦的做法。在这里使用是很巧妙的。
对于 1 到 n 每个数 i 我们随机一个整数(尽量随机范围大一点),作为 i 的哈希值。
我们把一段序列的哈希值设置为这个序列的数的哈希值的亦或值。
设置这两个哈希之后,我们考虑一个序列是一个排列,则必然两者的哈希值一样;反之哈希值一样,这个序列就很可能是一个排列。
我们处理 pre_hshi=hsh(a1)⊕hsh(a2)⊕...⊕hsh(ai) 。那么所求序列的哈希值就是 pre_hshr⊕pre_hshl−1 。这由亦或的性质是容易看出来的。然后判断这个数是否等于 hsh(1)⊕hsh(2)⊕...⊕hsh(r−l+1) ,就解决了这个问题。
这种方法显然实现更容易,而且复杂度也低。
https://code.csdn.net/snippets/1582908/master/hdu5172%281%29.cpp/raw