E05 线性DP U197280 最长公共子序列

E05 线性DP 最长公共子序列_哔哩哔哩_bilibili

 

U197280 【模板】最长公共子序列 - 洛谷

// 线性DP O(n^2)
#include<bits/stdc++.h>
using namespace std;

const int N=1010;
int n,m;
char a[N],b[N];
int f[N][N]; //f[i,j]表示前 i,j 个字符中的最长公共子序列的长度

int main(){
  cin>>a+1>>b+1;
  n=strlen(a+1); m=strlen(b+1);

  for(int i=1; i<=n; i++){
    for(int j=1; j<=m; j++){
      if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1;
      else f[i][j]=max(f[i-1][j],f[i][j-1]);
    }
  }
  cout<<f[n][m];
}

 

// 线性DP 滚动数组 O(n^2)
#include<bits/stdc++.h>
using namespace std;

const int N=10010;
int n,m;
char a[N],b[N];
int f[2][N]; //f[i,j]表示前 i,j 个字符中的最长公共子序列的长度

int main(){
  cin>>a+1>>b+1;
  n=strlen(a+1); m=strlen(b+1);
  
  int u=0;
  for(int i=1; i<=n; i++){
    u^=1;
    for(int j=1; j<=m; j++){
      if(a[i]==b[j]) f[u][j]=f[u^1][j-1]+1;
      else f[u][j]=max(f[u^1][j],f[u][j-1]);
    }
  }
  cout<<f[u][m];
}
// 线性DP 滚动数组 O(n^2)
#include<bits/stdc++.h>
using namespace std;

const int N=10005;
int n,m;
char a[N],b[N];
int f[2][N];

int main(){
  cin>>a+1>>b+1;
  n=strlen(a+1);m=strlen(b+1);
  
  for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      if(a[i]==b[j]) f[1][j]=f[0][j-1]+1;
      else f[1][j]=max(f[0][j],f[1][j-1]);
    }
    for(int j=1; j<=m; j++) f[0][j]=f[1][j];
  }
  cout<<f[1][m];
}

 

P2516 [HAOI2010] 最长公共子序列 - 洛谷

// 线性DP 滚动数组 O(n^2)
#include<bits/stdc++.h>
using namespace std;

const int N=5010,mod=1e8;
int n,m;
char a[N],b[N];
int f[2][N],g[2][N];

int main(){
  scanf("%s %s",a+1,b+1);
  n=strlen(a+1)-1; m=strlen(b+1)-1;
  
  for(int k=0; k<=m; k++) g[0][k]=1;
  g[1][0]=1;
  
  int u=0;
  for(int i=1; i<=n; i++){
    u^=1;
    for(int j=1; j<=m; j++){
      if(a[i]==b[j]) f[u][j]=f[u^1][j-1]+1;
      else f[u][j]=max(f[u^1][j],f[u][j-1]);
      g[u][j]=0;
      if(a[i]==b[j]&&f[u][j]==f[u^1][j-1]+1) g[u][j]+=g[u^1][j-1];
      if(f[u][j]==f[u^1][j]) g[u][j]+=g[u^1][j];
      if(f[u][j]==f[u][j-1]) g[u][j]+=g[u][j-1];
      if(f[u][j]==f[u^1][j-1]) g[u][j]-=g[u^1][j-1]; //容斥
      g[u][j]%=mod;
    }
  }
  printf("%d\n%d",f[u][m],g[u][m]);
}

 

P1439 两个排列的最长公共子序列 - 洛谷

// 二分+贪心 O(nlogn)
#include<bits/stdc++.h>
using namespace std;

const int N=100010;
int n,x,id[N],p[N],len;

int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++) scanf("%d",&x),id[x]=i;
  
  memset(p,0x3f,sizeof p);
  for(int i=1;i<=n;i++){
    scanf("%d",&x);
    *lower_bound(p+1,p+n+1,id[x])=id[x]; //用x的出现次序替换队列p中元素
  }
  len=lower_bound(p+1,p+n+1,p[0])-p-1; //第一个 0x3f 左边是公共子序列
  printf("%d",len);
}

 

U118717 最长公共上升子序列 - 洛谷

P10954 LCIS - 洛谷

// 线性DP O(n^3)
#include<bits/stdc++.h>
using namespace std;

const int N=3005;
int n,a[N],b[N],ans;
int f[N][N]; //f[i,j]表示前(i,j)个数且以 b[j] 为结尾的最长公共上升子序列的长度

int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  for(int i=1;i<=n;i++) scanf("%d",&b[i]);
  
  for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++){
      if(a[i]!=b[j]) f[i][j]=f[i-1][j];
      else{
        int mx=0;
        for(int k=1;k<j;k++) if(a[i]>b[k])mx=max(mx,f[i-1][k]);
        f[i][j]=mx+1;
      }
      ans=max(ans,f[i][j]);
    }
  }
  printf("%d",ans);
}
// 线性DP O(n^2)
#include<bits/stdc++.h>
using namespace std;

const int N=3005;
int n,a[N],b[N],ans;
int f[N][N]; //f[i,j]表示前(i,j)个数且以 b[j] 为结尾的最长公共上升子序列的长度

int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  for(int i=1;i<=n;i++) scanf("%d",&b[i]);
  
  for(int i=1;i<=n;i++){
    int mx=0;
    for(int j=1;j<=n;j++){
      if(a[i]!=b[j]) f[i][j]=f[i-1][j];
      else f[i][j]=mx+1; //用 1~[i-1,j-1] 的LCIS接上a[i]
      if(a[i]>b[j]) mx=max(mx,f[i-1][j]); //保存 1~[i-1,j] 以a[i]结尾的LCIS的长度
      ans=max(ans,f[i][j]);
    }
  }
  printf("%d",ans);
}

 

CF10D LCIS - 洛谷

// 线性DP O(n^2)
#include<bits/stdc++.h>
using namespace std;

const int N=3005;
int n,m,a[N],b[N],ans;
int f[N][N]; //f[i,j]表示前(i,j)个数且以 b[j] 为结尾的最长公共上升子序列的长度
int pre[N][N],path[N];

int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  scanf("%d",&m);
  for(int i=1;i<=m;i++) scanf("%d",&b[i]);
  
  for(int i=1;i<=n;i++){
    int mx=0,pos=0;
    for(int j=1;j<=m;j++){
      if(a[i]!=b[j]) f[i][j]=f[i-1][j],pre[i][j]=j;
      else f[i][j]=mx+1,pre[i][j]=pos;
      if(a[i]>b[j]) if(f[i-1][j]>mx) mx=f[i-1][j],pos=j;
    }
  }
  
  int mm;
  for(int j=1;j<=m;j++)if(f[n][j]>ans){
    ans=f[n][j];
    mm=j;
  }
  int i=n,j=mm,cnt=0;
  while(i||j){
    if(pre[i][j]!=j) path[++cnt]=b[j];
    j=pre[i][j];
    i--;
  }
  
  if(ans==0) {puts("0");return 0;}
  printf("%d\n",ans);
  for(int i=cnt;i>=1;i--)printf("%d ",path[i]);
  return 0;
}

 

posted @ 2023-04-09 23:12  董晓  阅读(1182)  评论(1)    收藏  举报