动态规划训练之十九

http://www.51nod.com/Challenge/Problem.html#problemId=1202

题目大意:

O(n)求出一个序列的本质不同的子序列个数

考虑动态规划:

dp[i]表示前i位子序列的个数

很显然如果没有本质不同的话,子序列个数等同于子集的个数就是2n-1

但关键就在于这个本质不同?怎么办?

当然考虑容斥

记vis[a[i]]表示上一次a[i]出现的位置

只要dp的时候减掉dp[vis[a[i]]-1]就减掉重复的了

code :

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
long long dp[100055];
long long a[100055];
long long vis[100055];
int main()
{
    int n, i;
    while(~scanf("%d", &n))
    {
        for(i = 1; i <= n; i++)scanf("%lld", &a[i]);
        memset(vis, 0, sizeof(vis));
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        for(i = 1; i <= n; i++)
        {
            dp[i] = (dp[i - 1]<<1) % mod;
            if(vis[a[i]])
                dp[i] = (dp[i] - dp[vis[a[i]] - 1] + mod) % mod,vis[a[i]] = i;
            else vis[a[i]] = i;
        }
        printf("%lld\n", dp[n] - 1);
    }
}
posted @ 2019-11-01 09:36  wzx_believer  阅读(113)  评论(0编辑  收藏  举报