CH5101 LCIS【线性dp】

5101 LCIS 0x50「动态规划」例题

描述

熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。
小沐沐说,对于两个数列A和B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。
奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。不过,只要告诉奶牛它的长度就可以了。数列A和B的长度均不超过3000。

输入格式

第一行N,表示A,B的长度。
第二行,串A。
第三行,串B。

输出格式

输出长度。

样例输入

4
2 2 1 3
2 1 2 3

样例输出

2

数据范围与约定

  • 1<=N<=3000,A,B中的数字不超过2^31-1

Contest Hunter - 信息学自助比赛平台

LIS与LCS问题的结合

dp[i][j]表示A1-Ai和B1-Bj中以Bj为结尾的LCIS的长度

那么当Ai != Bj 时 显然dp[i][j] = dp[i-1][j]

当Ai == Bj时 判断1-j中是否有Bk < Bj 取所有可能解的最大值加一

找k时可以for循环跑 那么总的复杂度是n^3

优化的算法是对于每一个i A[i]都没有变化 每次j增加 可能解的数量是递增的

每一次都记录当前j的最大可能解就可用于下一次更新了

“在实现状态转移方程时,要注意观察决策集合的范围随着状态的变化情况。对于“决策集合中的元素只增多不减少的”的情景,就可以像本题一样维护一个变量来记录决策集合的当前信息,避免重复扫描”

很坑的是第三组数据好像个数有问题还是怎么的?反正我输出时多了一个\n就WA,去掉\n就过了

n^2算法

 1 //#include <bits/stdc++.h>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<stdio.h>
 6 #include<cstring>
 7
 8 using namespace std;
 9 typedef long long int LL;
10
11 const int maxn = 3005;
12 int A[maxn], B[maxn];
13 int n;
14 int dp[maxn][maxn];
15
16 int main()
17 {
18         scanf("%d", &n);
19         for(int i = 1; i <= n; i++)
20             scanf("%d", &A[i]);
21         for(int i = 1; i <= n; i++)
22             scanf("%d", &B[i]);
23
24         //memset(dp, 0, sizeof(dp));
25         for(int i = 1; i <= n; i++){
26             int val = 0;
27             for(int j = 1; j <= n; j++){
28                 if(A[i] == B[j]){
29                     dp[i][j] = val + 1;
30                 }
31                 else{
32                     dp[i][j] = dp[i - 1][j];
33                 }
34                 if(B[j] < A[i]) val = max(val, dp[i - 1][j]);
35             }
36         }
37
38         int ans = 0;
39         for(int i = 1; i <= n; i++){
40             ans = max(ans, dp[n][i]);
41         }
42         //cout<<endl;
43         printf("%d", ans);
44         //scanf("%d", &n);
45     return 0;
46 }

n^3算法

 1 //#include <bits/stdc++.h>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<stdio.h>
 6 #include<cstring>
 7
 8 using namespace std;
 9 typedef long long int LL;
10
11 const int maxn = 3005;
12 int A[maxn], B[maxn];
13 int n;
14 int dp[maxn][maxn];
15
16 int main()
17 {
18         scanf("%d", &n);
19         for(int i = 1; i <= n; i++)
20             scanf("%d", &A[i]);
21         for(int i = 1; i <= n; i++)
22             scanf("%d", &B[i]);
23
24         //memset(dp, 0, sizeof(dp));
25         for(int i = 1; i <= n; i++){
26             for(int j = 1; j <= n; j++){
27                 if(A[i] == B[j]){
28                     for(int k = 0; k < j; k++){
29                         if(B[k] < A[i])
30                             dp[i][j] = max(dp[i - 1][k] + 1, dp[i][j]);
31                     }
32                 }
33                 else{
34                     dp[i][j] = dp[i - 1][j];
35                 }
36             }
37         }
38
39         int ans = 0;
40         for(int i = 1; i <= n; i++){
41             ans = max(ans, dp[n][i]);
42         }
43         //cout<<endl;
44         printf("%d", ans);
45         //scanf("%d", &n);
46     return 0;
47 }

原文地址:https://www.cnblogs.com/wyboooo/p/9739863.html

时间: 2024-11-02 16:59:53

CH5101 LCIS【线性dp】的相关文章

TYVJ1071 LCIS 线性DP+决策集优化

问题描述 TYVJ1071 题解 暴力\(\mathrm{DP}\) 首先,一个\(O(n^3)\)的解法: 设\(opt_{i,j}\)代表\(a\)的前\(i\)个和\(b\)的前\(j\)个的\(\mathrm{LCIS}\). 显然有: 1.\(a_i=b_j\) \[opt_{i,j}=opt_{i-1,j}\] 2.\(a_i≠b_j\) \[opt_{i,j}=max_{0 \le k < j,b_k<a_i} {opt_{i-1,k}}+1\] 于是得到代码: #include

uva 11584 Partitioning by Palindromes 线性dp

// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串的数目 // // f[i] = min(f[i],f[j-1] + 1(j到i是回文串)) // // 这道题还是挺简单的,继续练 #include <algorithm> #include <bitset> #include <cassert> #include <

uva 11552 Fewest Flops 线性dp

// uva 11552 Fewest Flops // // 二维线性dp // // 首先,在该块必须是相同的来信.首先记录每块有很多种书 // 称为是counts[i]; // // 订购f[i][j]它代表前i字母j为结尾的最小分块数 // // 假设第i块的開始字母与第i-1块的结束字母同样 // f[i][j] = min(f[i][j],f[i-1][k] + counts[i] - 1); // // 否则 // // f[i][j] = min(f[i][j],f[i-1][k

poj3267——线性dp

poj3267——线性dp The Cow Lexicon Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8458   Accepted: 3993 Description Few know that the cows have their own dictionary with W (1 ≤ W ≤ 600) words, each containing no more 25 of the characters 'a'

线性DP POJ2279 Mr.Young&#39;s Picture Permutations

Mr. Young's Picture Permutations Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1128   Accepted: 562 Description Mr. Young wishes to take a picture of his class. The students will stand in rows with each row no longer than the row behin

HDU 5074 Hatsune Miku (线性dp)

Hatsune Miku Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 654    Accepted Submission(s): 471 Problem Description Hatsune Miku is a popular virtual singer. It is very popular in both Japan

Codeforces 176B (线性DP+字符串)

题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成新串.问经过K次变形后,与目标串相同的变形方案数.mod 1000000007. 解题思路: 奇葩的字符串DP.照着别人的题解写的,解释不出原理是什么. 首先统计出经过1次变形,就能和目标串相同的中间产物串(包含源串)的个数cnt.len表示源串长度,那么len-cnt就表示和目标串不同的个数. 用

LightOJ1044 Palindrome Partitioning(区间DP+线性DP)

问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时候要枚举,这样时间复杂度是不可行的. 然后我就想降维度了,只能线性DP,dp[i]表示子串[0,i]的答案.这样可以从i-1转移到i,str[i]单独作一段或者str[i]能和前面的组成回文串,方程如下: dp[i]=min(dp[i-1]+1,dp[j-1]+1) (子串[j,i]是回文串) 现在

POJ 1958 Strange Towers of Hanoi (线性dp,记忆化搜索)

JQuery工具方法. (1)$.isNumeric(obj) 此方法判断传入的对象是否是一个数字或者可以转换为数字. isNumeric: function( obj ) { // parseFloat NaNs numeric-cast false positives (null|true|false|"") // ...but misinterprets leading-number strings, particularly hex literals ("0x...&

LA 4256 Salesmen 线性dp

// LA 4256 Salesmen 线性dp // // 像LCS和LIS问题类似,因为每次修改一个值,都是根据 // 前一个值决定的,那么最后一个结尾的数字肯定要作为 // 状态,而长度作为状态是一目了然的 // // d[i][j]表示长度为i,最后以j结尾的数组修改的最小次数 // // 则状态转移方程为 // // d[i][j] = min(d[i][j],d[i-1][k]+(j,k是否相同或者相邻?0:1)); // // 个人感觉还是比较明显的,最后的答案就是min(d[L]