子序列的个数 --- 庞果网

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ygrx/article/details/11810327

庞果网的新题目:

题目描述


本题同样来自caopengcs,只要你有兴趣,每个人都可以出题(出题入口在主页右侧边栏“贡献题目”->“我要发布”内),以下是题目详情:

  • 子序列的定义:对于一个序列a=a[1],a[2],......a[n],则非空序列a'=a[p1],a[p2]......a[pm]为a的一个子序列

    • 其中1<=p1<p2<.....<pm<=n。 例如:4,14,2,3和14,1,2,3都为4,13,14,1,2,3的子序列。
    • 对于给出序列a,有些子序列可能是相同的,这里只算做1个
  • 要求输出a的不同子序列的数量。

输入:

  • 长度为n的数组1<=n<=100,数组元素0<=a[i]<=110

输出:

  • 子序列 的个数对1000000007取余数的结果(由于答案比较大,输出Mod 1000000007的结果即可)

算法描述


刚开始的时候我总想着直接去算排列组合,然后根据容斥原理把重复的去掉,从而得到结果,后来发现这样不是不行,要考虑的东西实在是太多了,编程起来非常麻烦。放弃了。

后来休息了一天,再看的时候换了一个思路,仔细分析了一下题目,按照递推关系,找到一个比较靠谱的思路。

设 f(k)为k长度的序列的子序列个数,那么很显然有以下推论:

  • f(k)的个数包括f(k-1)的个数,因为f(k-1)的每一个都是f(k)的子序列,然后把f(k-1)的每个序列和a[k]组合起来,这些序列也是f(k)的子序列,个数还是f(k-1),载加上单独的a[k],那么

f(k)=2*f(k-1)+1

  • 上面这个表达式是当a[k]和前面的数都不同的时候的情况,如果a[k]在前面出现过的话,那f(k)的个数除了上面那些的话:

    • 还需要减去最近一次出现a[k]这个数值的地方-1的子序列个数,因为这些算重复了
    • +1也没有了,因为f(a[k]上次出现的位置)包括了a[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; 
	 }



猜你喜欢

转载自blog.csdn.net/ygrx/article/details/11810327