把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【Dp】子序列

题目描述

沙都子有一个序列,第i 个位置的数为ai。她知道,该序列共有2n − 1 个子序
列,但有一些子序列长得一样。于是她提出了一个问题:该序列的本质不同的
子序列有多少种呢?
对于1 ≤ p1 < p2 < · · · < pm ≤ n(m 是任意正整数),称(ap1 , ap2 , . . . , apm) 是
一个子序列。
两个子序列(ap1 , . . . , apl ) 和(aq1 , . . . , aqm) 本质相同,当且仅当l = m,且对所
有i = 1, . . . ,m 都满足api = aqi。

输入

第一行,一个整数n。
第二行,n 个非负整数ai。

输出

答案模10^9 + 7。

数据范围限制

对于25% 的数据,1 ≤ n ≤ 10。
对于50% 的数据,1 ≤ n ≤ 10^3。
对于100% 的数据,1 ≤ n ≤ 10^6,0 ≤ ai ≤ 10^6。

Solution:

这道题更像是一道基础的模型题目,题意十分简单,不难看出是一道统计类型的Dp
我们可以发现,对于以某一个Ai为结尾可构成的本质不同子序列当中,其实无非就两种情况,一个是自己单独成为一个子序列,另一个就是与之前已经形成的子序列连接起来构成新的子序列。
于是我们很容易得到一个基础的方程式:
但是如何保证本质不同呢?其实只要在每次方程减去所有同样以Ai结尾的f就好了

然后我们可以通过维护前缀和的方式来解决两个求和函数,将复杂度降低至O(N)

Code:

 1 #include<bits/stdc++.h>
 2 const int P=1e9+7;
 3 using namespace std;
 4 int Dp[1000132],A[1000123],Sum[1000123],Gp[1000123],N;
 5 int main()
 6 {
 7     scanf("%d",&N);
 8     for(int i=1;i<=N;i++)
 9         scanf("%d",&A[i]);
10     for(int i=1;i<=N;i++){
11         Dp[i]=(1+Sum[i-1]-Gp[A[i]])%P;
12         Sum[i]=(Sum[i-1]+Dp[i])%P;
13         Gp[A[i]]=(Gp[A[i]]+Dp[i])%P;
14     }
15     printf("%d",Sum[N]);
16     return 0;
17 }

 

 

 

posted @ 2020-08-22 17:10  fluoce  阅读(101)  评论(0编辑  收藏  举报

Contact with me