C语言之子序列个数

欢迎进入我的C语言世界

题目

Problem Description

子序列的定义:对于一个序列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,请输出不同的子序列的个数。(由于答案比较大,请将答案mod 1000000007)

Input

输入包含多组数据。每组数据第一行为一个整数n(1<=n<=1,000,000),表示序列元素的个数。

第二行包含n个整数a[i] (0<=a[i]<=1,000,000)表示序列中每个元素。

Output

输出一个整数占一行,为所求的不同子序列的个数。由于答案比较大,请将答案mod 1000000007。

Sample Input

4
1 2 3 2

Sample Output

13

答案

下面展示 实现代码

#include <stdio.h>
#include <string.h>
long long d[1000007];//d[i]表示前i个元素可以生产的不同的子序列的个数
int p[1000007]; //记录某元素最后一次出现的位置 
#define mod 1000000007
int main()
{
    
    
	int n;
	while(scanf("%d", &n) != EOF)
	{
    
    
		int i = 1;
		int a;//记录输入的序列 
		memset(d, 0, sizeof(d));
		memset(p, 0, sizeof(p));
		d[0] = 0;
		for(i = 1; i <= n; i++)
		{
    
    
			scanf("%d",&a);
			if(p[a] == 0)//a在之前没有出现过
			{
    
    
				d[i] = (2*d[i-1] + 1) % mod;
			}
			else
			{
    
    
				d[i] = (2*d[i - 1] - d[p[a] - 1] + mod) % mod;//d[p[a] - 1]表示a最近一次出现的位置的d 
				//加mod是因为有可能出现负数的情况 
			}
			p[a] = i;//a最近一次出现的位置 
		}
		printf("%d\n",d[n] % mod);
	}
	return 0;
 } 

本题感悟

本块内容可能来自课本或其他网站,若涉及侵权问题,请联系我进行删除,谢谢大家啦~

思路:
设d[i]表示前i个元素可以生产的不同的子序列的个数,a[i]为第i个元素

  1. 输入的a[i]在之前没有出现过
    则d[i]由三部分组成:
    ①d[i-1]:前i-1也是i的子序列;
    ②每个d[i-1]后面跟上a[i]:又会组成d[i-1]个新的子序列;
    ③a[i]:自成一个子序列
    所以d[i] = 2*d[i-1] + 1
  2. 输入的a[i]在之前出现过
    记录最近出现的位置p[ a[i] ];初始化p数组为0,即每一个数字都没有出现过,出现后再记录p[ a[i] ] = i; //a[i]最近出现的位置 则1中的三种情况的第三种不存在,第一二种合并后要减去重复的(即上次出现的子序列),即减去d[ p[a[i]] - 1 ]

以上。

猜你喜欢

转载自blog.csdn.net/hongguoya/article/details/105821341