题目链接:
https://www.51nod.com/onlineJudge/submitDetail.html#!judgeId=250782
题解:
一道很好的dp的题目,这里我用的是一维的dp[i],i表示的是位置是i的时候能够组成的不同子序列的个数。
在不考虑重复的情况下,我们可以很容易的推出这个dp的转移的方程
dp[i] =dp[i-1]*2+1;
但是在我们考虑到重复的情况的时候,我们可以这么想,在原本直接乘2的基础上加的1改成乘2在减去之前已将出现过的这个元素的个数。
dp[i]=dp[i-1]*2-pos[num[i]-1];(这里减1,有点像求前缀和)
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
const int maxn = 1e6+10;
typedef long long ll;
const ll mod = 1e9+7;
ll num[maxn];
ll pos[maxn];
ll dp[maxn];
int main()
{
ll n;
while(scanf("%lld",&n)!=EOF)
{
for(ll i=0;i<n;i++)
scanf("%lld",&num[i]);
met(dp,0);
met(pos,-1);
dp[0]=1;
pos[num[0]]=0;// 初始化
for(ll i=1;i<n;i++)
{
if(pos[num[i]]==-1)
dp[i]=dp[i-1]*2+1;
else
dp[i]=dp[i-1]*2-dp[pos[num[i]]-1];
pos[num[i]]=i;
dp[i]=(dp[i]+mod)%mod;
}
printf("%lld\n",(dp[n-1]+mod)%mod);
}
}