P1439 【模板】最长公共子序列

题意:给出两个序列,求最长公共子长度

思路:第一种直接暴力,代码如下:

 1 #include<iostream>
 2 using namespace std;
 3 const int maxn=1e5+10;
 4 int dp[maxn][maxn];
 5 int a1[maxn],a2[maxn],n,m;
 6 int main()
 7 {
 8     //dp[i][j]表示两个串从头开始,直到第一个串的第i位 
 9     //和第二个串的第j位最多有多少个公共子元素 
10     cin>>n>>m;
11     for(int i=1;i<=n;i++)scanf("%d",&a1[i]);
12     for(int i=1;i<=m;i++)scanf("%d",&a2[i]);
13     for(int i=1;i<=n;i++)
14     for(int j=1;j<=m;j++){
15         dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
16         if(a1[i]==a2[j])
17         dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
18         //因为更新,所以++; 
19     }
20     cout<<dp[n][m];
21 }
View Code

  但是这种方法在数据到达1e4 、1e5时,就会超时;而暴力方法在转移的时候有许多无用的转移点

  所以引入一种二分的方法 把复杂度降低道n*logn

  因为本题所有数据都是唯一的,即某个数在某一序列中最多出现一次;所以可以用mp来标记位置;

  我们开一个f【】数组,记录的不再是长度,而是在某一长度下的到达的位置的最小值

     什么意思呢?  我们有两个序列,我们是拿第二个序列跟第一个序列层层比较的

      比如f【1】=2,就是有一个公共子的情况下,跟a序列比较到的最小位置是到第二个位置,即第二个后面的数还没比较过

         那么如何二分呢?二分要记录些什么呢?  

            自然二分要记录的就是,在某一长度下,a序列到达的最小位置,

              因为按这一计算方法,f序列递增,所以满足二分的要求

    那么二分的时候,我们就找到第一个大于mp【b【j】】的数,为什么一定要这个数呢?

      假如是这个数左边的数,那他左边的数肯定小于mp【b【j】】,自然无法做状态转移

      假如如果是右边的数,那么如果把这个数强加在右边的数上边的话,就会导致这个位置的长度变小,不满足

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int inf=0x3f3f3f3f;
 4 const int maxn=1e5+10;
 5 int a[maxn],b[maxn];
 6 int mp[maxn],f[maxn];
 7 int main()
 8 {
 9     int n;
10     cin>>n;
11     for(int i=1;i<=n;i++){
12         scanf("%d",&a[i]);
13         mp[a[i]]=i;
14     }
15     for(int i=1;i<=n;i++){
16         scanf("%d",&b[i]);
17         f[i]=inf;
18     }
19     int len=0;
20     f[0]=0;
21     for(int i=1;i<=n;i++){
22         int l=0,r=len,mid;
23         if(mp[b[i]]>f[len])f[++len]=mp[b[i]];
24         else{
25             while(l<r){
26                 mid=(l+r)/2;
27                 if(f[mid]>mp[b[i]])r=mid;
28                 else l=mid+1;
29             }
30             f[l]=min(mp[b[i]],f[l]);
31         }
32     }
33     cout<<len;
34     return 0;
35 }
View Code

 

           

posted @ 2020-04-03 12:46  古比  阅读(216)  评论(0编辑  收藏  举报