去重的优化
具体的戳罗总博客~
题目大意
给定一个序列,包含n个整数,每个整数不大于231,输出它的前P个不递减序列,如果不够P个,就输出所有的。不递减序列见这个例子:3个整数{1, 3, 2},它的前5个序列是{1}、{3}、{2}、{1, 3}、{1, 2};输出时,首先按子序列长度排序,相同长度的,按出现顺序排序,所以{3}在{2}前面,{1, 3}在{1, 2}前面。这个例子里没有长度为3的不递减序列。1<n≤1000,1<p≤10000。
解题思路
1.去重的优化
用某元素a为首元素,在原始序列中生成不递减子序列后,后面如果再遇到相等的a,就不用再生成子序列了,因为前面已经用a在整个范围内搜过了;这个思路可以推广到第二个元素、第三个元素等等。
下面以序列A[]={1, 2, 1, 5, 1, 4, 1, 7}为例说明,它的不递减子序列有{1}、{2}、{5}、{4}、{7}、{1, 2}、{1, 1}、{1, 5}、{1, 4}、{1, 7}、{2, 5}、{2, 4}、{2, 7}、{5, 7}等等。
①以A[0]=1为首,生成了{1}、{1,2}、{1,1}、{1,5}、{1,4}等序列;下次准备以A[2]=1为首生成子序列时,发现前面有A[0]=A[2]=1,那么就丢弃以A[2]=1为首的所有子序列,因为前面已经用A[0]=1为首,在整个序列中得到了{1}、{1,5}、{1,4}等序列。
②以A[3]=5为首的子序列,确定子序列的第二个元素时,在A[3]后面的{1, 4, 1, 7}范围内,按①的方法操作,例如检查{1, 7}的1时,这个1已经在{1, 4, 1, 7}的第一个位置出现过,所以应该丢弃。
复杂度分析:上面的去重方法,对一个子序列做一次判重的复杂度是 O ( n ) O(n) O(n)的,似乎比STL set的 O ( l o g n ) O(logn) O(logn)差;不过,前者剪去了很多子序列,需要判重的子序列比后者少很多。
代码中具体实现:选择下一个数的时候,当前要填的位置如果选了 a a a,继续遍历原序列找可以填的数时,就不再用 a a a 生成子序列。
for(int i = cur + 1; i <= n; ++i) {
...
bool ok = true;
for(int j = cur + 1; j < i; ++j) {
if (a[j] == a[i