子序列个数
欢迎进入我的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个元素
- 输入的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 - 输入的a[i]在之前出现过
记录最近出现的位置p[ a[i] ];初始化p数组为0,即每一个数字都没有出现过,出现后再记录p[ a[i] ] = i; //a[i]最近出现的位置 则1中的三种情况的第三种不存在,第一二种合并后要减去重复的(即上次出现的子序列),即减去d[ p[a[i]] - 1 ]
以上。