本题同样来自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的结果即可)。
首先感谢cp大神,在这一题上有着巨大的帮助,因为之前理解题意的原因,一直认为测试点有问题,后来茅塞顿开,终于理解了题意;
题目中的实例有一定的特殊性,假如给的序列为{1, 1, 4, 1};
则其子序列有“1”,“4”,“1, 1”,“1, 4”,"4, 1","1, 1, 4",“1, 1, 1”,“1, 4, 1”,以及"1, 1, 4, 1"共九种;
如果这个序列没有重复数据的话,很明显这就是一个集合的问题了;
不过当出现重复的话,此时的解法就不一样了:
如果未发生重复现象,则子序列的个数随着个数的增加,其个数sum[i] = sum[i - 1] + dp[i];此时dp[i] = sum[i - 1];
若之前发生的重复现象,即exist[x] != 0;此时的dp[i]就会发生与之前出现x值重复的组合,此时dp[i] = sum[i - 1]; dp[i] -= sum[exist[x] - 1];
继续深究,贴个代码:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
const int M = 1000000007;
using namespace std;
int run(const int *a, int n) {
int exist[111] = {0}; //判断是否存在,数组元素0<=a[i]<=110
int dp[101] = {0};
int sum[101] = {1}; //个数
int x;
for (int i = 1; i <= n; ++i)
{
x = a[i - 1]; //一个一个读取元素
dp[i] = sum[i - 1]; //
if (exist[x] != 0 )
{
dp[i] -= sum[exist[x] - 1]; //之前出过此值,出现重复
if(dp[i] < 0)
dp[i] += M;
}
exist[x] = i; //记录最近出现x的下标
sum[i] = sum[i - 1] + dp[i]; //更新子序列个数
if (sum[i] >= M) //超限则进行-M,重新在表示范围内
{
sum[i] -= M;
}
}
if (--sum[n] < 0) //-1
{
sum[n] += M;
}
return sum[n];
}
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{
int a[] = {1, 1, 4, 1};
int length = sizeof(a) / sizeof(int);
cout<<run(a, length);
return 0;
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。
多多交流...o(∩_∩)o