zoukankan      html  css  js  c++  java
  • 子序列的个数(DP计数)

    这个问题让我知道了动态规划除了能用来求最优解,还可以用来做计数 = =

    然后,取模的时候如果有减法是这个样子取模的: (a-b)%MOD = ((a-b)%MOD+MOD)%MOD;

    因为(a-b)可能会产生负数。

    问题概述:

    给定一个正整数序列,序列中元素的个数和元素值大小都不超过105, 求其所有子序列的个数。

    注意相同的只算一次:例如 {1,2,1}有子序列{1} {2} {1,2} {2,1}和{1,2,1}。最后结果对10^9 + 7取余数。

    子序列的定义:对于一个序列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的子序列。
     
    输入

    第1行:一个数N,表示序列的长度(1 <= N <= 100000) 第2 - N + 1行:序列中的元素(1 <= a[i] <= 100000)

    输出

    输出a的不同子序列的数量Mod 10^9 + 7。

    解决:

    首先,这个题并不能采用暴力枚举的方式的来解决。对于一个非空集合,它的子集个数是2^n(含空集),n的范围太大了。

    我们来考虑动态规划,假设 dp[i] 表示到第 i 个元素时已形成的不重复的子序列个数(含空),数组下标从1开始;初始dp[0] = 1, 对应空集。

    考虑第 i 项:

       如果之前一直没有重复的元素,那么 dp[i] 的值就是 dp[i-1] * 2 ,因为前面已经形成了 dp[i-1] 个值,后来加入的新元素 a[i] 可以和前面的

    dp[i-1]个 序列都组成一个新序列, 所以dp[i] = dp[i-1] * 2 。

      那如果有重复的呢,我们假设这个数上一次在数组的 j 位置出现过,那么我们这种 dp[i] = dp[i-1] * 2 的计算就会有重复, 那是那些地方有重复呢,

    对啦,就是位置 j 那里了,位置 j 之前的数又被我们重复计算了一次。而我们多算的次数其实就是 dp[j-1] 。于是我们有了递推式:

    dp[i] = dp[i – 1] * 2   (如果a[i]之前没有出现)
    dp[i] = dp[i – 1] * 2 – dp[j – 1]   (如果a[i]最近在j的位置出现过)

    怎么保存a[i] 最近一次出现的位置就留给大家思考啦~

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define MOD 1000000007
     5 #define maxn 100005
     6 #define ll __int64 
     7 using namespace std;
     8 ll dp[maxn];
     9 int a[maxn],have[maxn];
    10 int main()
    11 {
    12     int n;
    13     memset(have,0,sizeof(have)); // 用来保存 a[i] 最近一次出现位置的数组 
    14 //    memset(dp,0,sizeof(dp));
    15     dp[0]=1;         //初始化 
    16     scanf("%d",&n);    
    17     for(int i=1;i<=n;i++)
    18     {
    19         scanf("%d",&a[i]);  
    20         if(have[a[i]] > 0) dp[i] = ( ( (dp[i-1] * 2) - (dp[have[a[i]]- 1]) ) % MOD + MOD) % MOD;    // 减法的取余 
    21         else dp[i] = (dp[i-1] * 2) % MOD;    
    22         have[a[i]] = i;    
    23     }    
    24     printf("%I64d
    ",dp[n]-1);
    25     return 0;    
    26 }
  • 相关阅读:
    解决Xcode8打印了nw_socket_handle_socket_event Event mask
    调用系统框架使用设备系统语言的设置,相册相机设置为中文
    ios开发 之 设置多种文字颜色/背景色/文字下划线/行间距 NSString
    IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法
    UITableView设置cell的separator 分割线
    iOS用户点击推送消息进入应用后自动跳转到对应的ViewController
    随感
    JS获取当前网页大小以及屏幕分辨率等
    js将秒转换为 分:秒 函数
    css实现强制不换行/自动换行/强制换行
  • 原文地址:https://www.cnblogs.com/ember/p/4718334.html
Copyright © 2011-2022 走看看