子序列的个数(DP计数)

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

然后,取模的时候如果有减法是这个样子取模的: (a-b)%MOD = ((a-n)%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\n",dp[n]-1);
25     return 0;
26 }
时间: 2024-08-30 14:48:01

子序列的个数(DP计数)的相关文章

FZUProblem 2129 子序列个数(dp)

 Problem 2129 子序列个数 Accept: 147    Submit: 432 Time Limit: 2000 mSec    Memory Limit : 32768 KB  Problem Description 子序列的定义:对于一个序列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,1

[LeetCode] Count Different Palindromic Subsequences 计数不同的回文子序列的个数

Given a string S, find the number of different non-empty palindromic subsequences in S, and return that number modulo 10^9 + 7. A subsequence of a string S is obtained by deleting 0 or more characters from S. A sequence is palindromic if it is equal

HDU-1257 最少拦截系统 贪心/DP 最长上升子序列的长度==最长不上升子序列的个数?

题目链接:https://cn.vjudge.net/problem/HDU-1257 题意 中文题咯中文题咯 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少

Distinct Subsequences(不同子序列的个数)——b字符串在a字符串中出现的次数、动态规划

Given a string S and a string T, count the number of distinct subsequences ofT inS. A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative po

ZOJ3380- Patchouli&#39;s Spell Cards(概率DP+计数)

Patchouli's Spell Cards Time Limit: 7 Seconds      Memory Limit: 65536 KB Patchouli Knowledge, the unmoving great library, is a magician who has settled down in the Scarlet Devil Mansion (紅魔館). Her specialty is elemental magic employing the seven ele

动态规划(DP计数):HDU 5116 Everlasting L

Matt loves letter L. A point set P is (a, b)-L if and only if there exists x, y satisfying: P = {(x, y), (x + 1, y), . . . , (x + a, y), (x, y + 1), . . . , (x, y + b)}(a, b ≥ 1) A point set Q is good if and only if Q is an (a, b)-L set and gcd(a, b)

CSU 1354 Distinct Subsequences 求不相同子序列的和 dp

题目链接:点击打开链接 Description Give a positive number, count the sum of the distinct subsequence of it, moreover, any subsequence should not contain leading zeroes except it is zero. For example, if the number is 1022, the answer is 1 + 0 + 2 + 10 + 12 + 22

Leetcode 673.最长递增子序列的个数

最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]. 示例 2: 输入: [2,2,2,2,2] 输出: 5 解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5. 注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数. 思路 定义 dp(n,1) cnt (n,1) 这里我用dp[i]

Q673 最长递增子序列的个数

给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]. 示例 2: 输入: [2,2,2,2,2] 输出: 5 解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5. 注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数. class Solution { public int findNumberOfLIS(