子序列的个数 --- 庞果网
庞果网的新题目:
本题同样来自caopengcs,只要你有兴趣,每个人都可以出题(出题入口在主页右侧边栏“贡献题目”->“我要发布”内),以下是题目详情:
子序列的定义:对于一个序列a=a[1],a[2],......a[n],则非空序列a'=a[p1],a[p2]......a[pm]为a的一个子序列
要求输出a的不同子序列的数量。
输入:
输出:
刚开始的时候我总想着直接去算排列组合,然后根据容斥原理把重复的去掉,从而得到结果,后来发现这样不是不行,要考虑的东西实在是太多了,编程起来非常麻烦。放弃了。
后来休息了一天,再看的时候换了一个思路,仔细分析了一下题目,按照递推关系,找到一个比较靠谱的思路。
设 f(k)为k长度的序列的子序列个数,那么很显然有以下推论:
f(k)=2*f(k-1)+1
上面这个表达式是当a[k]和前面的数都不同的时候的情况,如果a[k]在前面出现过的话,那f(k)的个数除了上面那些的话:
f(k)=2*f(k-1)-f(a[k]上次出现的位置-1)
有了这两个表达式,就是一个完整的递推关系了,a[k]上次出现的位置的保存,可以用一个hash表来存储,这样速度很快,但是题目说a[k]的范围是0到220,那可以用一个220的数组来存储,反正也不会溢出,省得用hash了。
代码比较简单,具体的可以上github上看
subArray[0]=0;for(int i=1;i<=n;i++) { if(lastSameIndex[a[i-1]] == 0 ) { subArray[i]=(subArray[i-1]*2)+1; } else { subArray[i]=((subArray[i-1]*2)-subArray[lastSameIndex[a[i-1]]-1]); } lastSameIndex[a[i-1]]=i; }