题目链接:

https://www.luogu.org/problemnew/show/CF10D

方法一

分析

\(LCS\)和\(LIS\)已经成烂大街的知识了,可是当这两个合并起来成为\(LCIS\),解决的方式方法也多了起来.

首先有种最朴素的\(O(N^4)\)方法,\(f[i][j]\)表示A串第\(i\)个字母和B串第\(j\)个字母结尾的状态中\(LCIS\)的长度,那么

那么如果\(a[i]==b[j],f[i][j]=max_{0<=k<j且b[k]<a[i](b[j])}(f[i-1][k])+1\)

否则\(f[i][j]=f[i-1][j]\)

但是这种方法怎么打印方案呢?我们用\(path[j][len[j]]\)表示以\(j\)结尾的\(LCIS\)方案,\(len[j]\)指的是以\(j\)结尾的\(LCIS\)长度

这样我们从\(k\)更新到\(j\)时,首先将\(path[k][len[k]]\)全部复制到\(path[j][len[j]]\);

然后\(len[j]=len[k]+1,path[j][len[j]]=b[j]\)

跑时950+ms

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <queue>
#include <vector>
#define ll long long
#define ri register int
using std::max;
using std::min;
using std::swap;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
const int maxn=505;
const int inf=0x7fffffff;
int n,m,a[maxn],b[maxn],f[maxn][maxn],len[maxn];
int path[maxn][maxn];
void print(int x){
for(ri i=1;i<=len[x];i++)printf("%d ",path[x][i]);
puts("");
return ;
}
int main(){
int x,y,z;
int ans=-inf,ed=0;
read(n);
for(ri i=1;i<=n;i++){read(a[i]);}
read(m);
for(ri i=1;i<=m;i++){read(b[i]);}
a[0]=b[0]=-inf;
for(ri i=1;i<=n;i++){
for(ri j=1;j<=m;j++){
if(a[i]==b[j]){
for(ri k=0;k<j;k++){
if(b[k]<a[i]){
//f[i][j]=max(f[i][j],f[i-1][k]+1);
if(f[i][j]<f[i-1][k]+1){
f[i][j]=f[i-1][k]+1;
len[j]=len[k]+1;
for(ri p=1;p<=len[k];p++)path[j][p]=path[k][p];
}
}
}
}
else f[i][j]=f[i-1][j];
//ans=max(ans,f[i][j]);
path[j][len[j]]=b[j];
if(ans<f[i][j]){
ans=f[i][j];
ed=j;
}
}
}
printf("%d\n",ans);
print(ed);
return 0;
}

方法二

我们考虑递推时的决策集合,\(f[i][j]\)都是由\(f[i][k](b[k]<a[i])\)递推得到,那么我们如果在从\(f[i][0]\)递推到\(f[i][j]\)时我们已经记录下所有\(f[i][k]\)的最大值设为\(val\),直接将\(f[i][j]\)设为\(max(f[i][j],val+1)\)就好了,打印路径的方法跟方法一类似

这样时间复杂度能少个\(N\)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <queue>
#include <algorithm>
#define ll long long
#define ri register int
#define ull unsigned long long
using std::min;
using std::max;
using std::swap;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
const int maxn=505;
const int inf=0x7ffffff;
int n,m,a[maxn],b[maxn],f[maxn][maxn],path[maxn][maxn],len[maxn],ed;
int main(){
read(n);
for(ri i=1;i<=n;i++){
read(a[i]);
}
read(m);
for(ri i=1;i<=m;i++){
read(b[i]);
}
int ans=-inf,val,lst=0;
for(ri i=1;i<=n;i++){
lst=0;
val=f[i-1][0];
for(ri j=1;j<=m;j++){
if(a[i]==b[j]){
if(val+1>f[i][j]){
f[i][j]=val+1;
for(ri k=1;k<=len[lst];k++)path[j][k]=path[lst][k];
len[j]=len[lst]+1;
}
}
else f[i][j]=f[i-1][j];
path[j][len[j]]=b[j];
//ans=max(ans,f[i][j]);
if(f[i][j]>ans){
ans=f[i][j];
ed=j;
}
if(b[j]<a[i]){
//val=max(val,f[i-1][j]);
if(val<f[i-1][j]){
val=f[i-1][j];
lst=j;
}
}
}
}
printf("%d\n",ans);
//printf("%d %d\n",ed,len[ed]);
for(ri i=1;i<=len[ed];i++)printf("%d ",path[ed][i]);
return 0;
}

当然题解中还有\(O(1)\)记录路径的方法,以及\(O(N)\)的空间复杂度方法,这里先挖个坑吧

CF10D-LCIS题解--线性DP+打印方案的更多相关文章

  1. CF10D LCIS(线性DP)

    题意:\(LCIS\)输出方案 变迁の时刻,标记它 P.S:特判没\(LCIS\)的情况 //#include <iostream> #include <cstdio> #in ...

  2. HDU2929 Bigger is Better[DP 打印方案 !]

    Bigger is Better Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  3. BestCoder Round #87 1002 Square Distance[DP 打印方案]

    Square Distance  Accepts: 73  Submissions: 598  Time Limit: 4000/2000 MS (Java/Others)  Memory Limit ...

  4. CH5101 LCIS【线性dp】

    5101 LCIS 0x50「动态规划」例题 描述 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了 ...

  5. HDU 2296 Ring [AC自动机 DP 打印方案]

    Ring Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissio ...

  6. 【题解】POJ1934 Trip (DP+记录方案)

    [题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...

  7. 线性DP总结(LIS,LCS,LCIS,最长子段和)

    做了一段时间的线性dp的题目是时候做一个总结 线性动态规划无非就是在一个数组上搞嘛, 首先看一个最简单的问题: 一,最长字段和 下面为状态转移方程 for(int i=2;i<=n;i++) { ...

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

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...

  9. 线性dp

    线性dp应该是dp中比较简单的一类,不过也有难的.(矩乘优化递推请出门右转) 线性dp一般是用前面的状态去推后面的,也有用后面往前面推的,这时候把循环顺序倒一倒就行了.如果有的题又要从前往后推又要从后 ...

随机推荐

  1. react 实现数据双向绑定

    好久没有更新了 只是都写在有道笔记中 今天整理下 一些基础的 大神勿喷 一个基础的不能再基础的数据双向绑定 因为react不同于vue 没有v-model指令 所以怎么实现呢? import Reac ...

  2. 问题解决:fatal error C1083: 无法打开包括文件:No such file or directory

    fatal error C1083: 无法打开包括文件:No such file or directory将别的工程直接用VS2010打开出现了该问题,此时必须检查是不是: 1. 如果要引入的这些.h ...

  3. wpf相关好资源

    Textbox Drag/Drop in WPFhttp://www.codeproject.com/Articles/42696/Textbox-Drag-Drop-in-WPF.aspx Odys ...

  4. 线程池小结(JDK8)

    1.线程池的好处 降低资源消耗(重复利用已创建的线程减少创建和销毁线程的开销) 提高响应速度(无须创建线程) 提高线程的可管理性 2.相关类图 JDK5以后将工作单元和执行机制分离开来,工作单元包括R ...

  5. 7. grep

    grep命令 grep grep是通用正则表达式分析程序(General Regular Expression Parser)的缩写. grep命令可以在它的输入中搜索指定的字符串模式(Pattern ...

  6. 【Java】生成随机的手机号码并输出到文件

    import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.R ...

  7. python基础知识(集合)

    集合 可变集合set()/不可变集合frozenset() {}  大写的拉丁字母 用于保存不重复元素.无序不能通过索引来获取 集合的创建 空集合 使用set()函数 变量名 = set() 集合的添 ...

  8. springboot使用elasticsearch的客户端操作eslaticsearch

    一  ES客户端 ES提供多种不同的客户端: 1.TransportClient ES提供的传统客户端,官方计划8.0版本删除此客户端. 2.RestClient RestClient是官方推荐使用的 ...

  9. element-ui--按需引入

    参考链接:https://www.cnblogs.com/qiezuimh/p/10103522.html

  10. Apache——开启个人用户主页功能

    个人主页功能分为不加密和加密两种 不加密: 先来建立几个用户,我这是建了两个 例:命令为:useradd  qiyuan 然后输入:passwd qiyuan,改一下密码 我们看一下家目录下面: 已经 ...