[codevs2185]最长公共上升子序列

试题描述

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

输入

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

输出

输出长度。

输入示例

4
2 2 1 3
2 1 2 3

输出示例

2

数据规模及约定

1<=N<=3000,A,B中的数字不超过maxlongint

题解

首先果断想一个 n2logn 的做法:令 f(i, j) 表示考虑了第一个串的前 i 位,第二个串的前 j 位,最长公共上升子序列的末位是 B[j] 的最长公共上升子序列长度;那么如果 A[i] = B[j],就是所有满足 B[k] < B[j] 且 k < j 的 f(i-1, k) 转移到 f(i, j),否则 f(i, j) = f(i-1, j),于是我们可以随着 j 的递增将所有 f(i-1, j) 扔进树状数组,每次转移时查询一下前缀最大值就好了。

然后发现 n2 做法更 SB:由于我们每次在树状数组上询问的前缀都是 [1, A[i] ](因为只有当 A[i] = B[j] 时才会有转移),所以直接用一个变量存满足 B[k] < A[i] 且 k < j 的 f(i-1, k) 的最大值就好了。注意这里要用滚动数组,滚动数组用起来很方便,因为所有没更新过的 f(i, j) 就等于 f(i-1, j),所以 i 每加 1,直接在上一个版本的滚动数组上做就行了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
	if(Head == Tail) {
		int l = fread(buffer, 1, BufferSize, stdin);
		Tail = (Head = buffer) + l;
	}
	return *Head++;
}
int read() {
	int x = 0, f = 1; char c = Getchar();
	while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); }
	while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); }
	return x * f;
}

#define maxn 3010

int n, A[maxn], B[maxn], f[maxn];

int main() {
	n = read();
	for(int i = 1; i <= n; i++) A[i] = read();
	for(int i = 1; i <= n; i++) B[i] = read();

	int ans = 0;
	for(int i = 1; i <= n; i++) {
		int mx = 0;
		for(int j = 1; j <= n; j++) {
			if(B[j] < A[i]) mx = max(mx, f[j]);
			if(A[i] == B[j]) f[j] = max(f[j], mx + 1);
			ans = max(ans, f[j]);
		}
	}

	printf("%d\n", ans);

	return 0;
}

当然这题 n2logn 也是能过的。据说有人 n3 大力过去了。。。

时间: 2024-12-15 05:26:11

[codevs2185]最长公共上升子序列的相关文章

最长公共上升子序列(codevs 2185)

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

POJ 2127 最长公共上升子序列

动态规划法: #include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #include <cstring> #inc

最长公共上升子序列(LCIS)ZOJ 2432

立方算法: #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define M 505 using namespace std; typedef long long LL; LL a[M],b[M]; int dp[M][M]; int main() { //freopen("in.txt","r",stdin); in

动态规划——最长公共上升子序列LCIS

问题 给定两个序列A和B,序列的子序列是指按照索引逐渐增加的顺序,从原序列中取出若干个数形成的一个子集,若子序列的数值大小是逐渐递增的则为上升子序列,若A和B取出的两个子序列A1和B1是相同的,则A1/B1为A和B的公共子序列.求出A和B的最长公共上升子序列. 分析     结合最长公共子序列和最长上升子序列来解决这个问题,定义状态dp[i][j]表示A串中前i个字符和B串中前j个字符且以B[j]为结尾的最长公共上升子序列的长度.则有状态转移方程:[在进行动态规划状态的设计的时候,要简单.详尽的

Codeforces 10D LCIS 求最长公共上升子序列及输出这个子序列 dp

题目链接:点击打开链接 题意: 给定n长的一个序列 再给定k长的一个序列 求LCIS并输出这个子序列 如有多解输出任意解.. = - = 敲的时候听着小曲儿pre的含义还没有想清楚,万万没想到就过了... #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<mat

HDU 4512 最长公共上升子序列

各种序列复习: (1)最长上升子序列. 1.这个问题用动态规划就很好解决了,设dp[i]是以第i个数字结尾的上升子序列的最长长度.那么方程可以是dp[i]=max(dp[j]+1).(j<i).复杂度为O(n^2); 2.另外有一个该经典问题的O(nlogn)算法. 首先知道,当求dp[i]时,如果出现a[k]<a[j],而dp[k]=dp[j]时,应当优先选k吧.那么,既然每次选的都是较小,就可以把字符串按照dp[t]=k这个子序列长度分类.当同样dp[t]=k时,记录下该长度的最小的a[p

BNUOJ 4215 最长公共连续子序列

最长公共连续子序列 Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main 给你两个序列S1和S2,长度分别是L1,L2 (1 <= L1 , L2 <= 180). 写一个程序找出最长的连续公共子序列. 连续子序列定义为序列中连续的一个片段.例如序列"1 2 3"的子串有空串,"1","2",

UVA 12511/CSU 1120 virus 最长公共上升子序列

第一次接触一个这最长公共上升子序列 不过其实搞清楚了跟最长公共子序列和 最长上升子序列如出一辙 两重循环,对于当前不相等的,等于前一个的值,相等的,等于比当前A[i]小的最大值+1.弄个临时变量记录最大值即可 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int dp[2][1010]; int A[1010

HDU 4512 吉哥系列故事——完美队形I(LCIS最长公共上升子序列)

http://acm.hdu.edu.cn/showproblem.php?pid=4512 题意: 吉哥这几天对队形比较感兴趣. 有一天,有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形成一个新的队形,新的队形若满足以下三点要求,则称之为完美队形: 1.挑出的人保持他们在原队形的相对顺序不变: 2.左右对称,假设有m个人形成新的队形,则第1个人和第m个人身高相同,第2个人和第m-1个人身高相同,依此类推,当然,如果m是奇数,