算法分析:
设 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了。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1e6 + 5;
const int mod = 1000000007;
long long f[maxn]; //避免超int
int A[maxn], ls[maxn];
int main()
{
int n;
while(~scanf("%d", &n)) {
memset(ls, 0, sizeof(ls));
for(int i = 1; i <= n; i++) {
scanf("%d", &A[i]);
}
for(int i = 1; i <= n; i++) {
if(ls[A[i]] == 0) f[i] = (2 * f[i - 1] + 1) % mod;
else f[i] = (2 * f[i - 1] - f[ls[A[i]] - 1] + mod) % mod;
ls[A[i]] = i;
}
printf("%lld\n", f[n]);
}
return 0;
}