zoukankan      html  css  js  c++  java
  • Luogu P1439 【模板】最长公共子序列

      又是模板题呵,但这次的难度有点增加。

      先看题目第一个想到DP的经典算法,要O(n^2),然后想其它的算法。

      其实我们衢州市一次联考有一题很像这题,不过还要难一点。

      思想是离散化+最长不下降子序列(在这里和最长上升子序列等价,因为没有重复的值)

      先离散一下第二串里每个点的第一串里的位置(数组也可以,但我喜欢用map),如样例:

      5 

      3 2 1 4 5
      1 2 3 4 5

      散出来就是 3 2 1 4 5,然后为了使他们公共最长,想到什么?

      最长不下降子序列!为什么?

      刚开始做的是根据他们的数值,但现在将他们转化成了标号(important)

      对于第一串的标号,很简单,就是1~n(自己对应自己的位置)

      然后剩下的就是在第二串里找最长的递增作为它的重复部分了。

      如果裸的最长不下降子序列(DP),复杂度也是O(n^2),贴一下代码,但道理应该大多数OI的书上都有

      50CODE

    #include<cstdio>
    #include
    <map> using namespace std; inline void read(int &x) { x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } inline int max(int a,int b) { return a>b?a:b; } const int N=100005; map <int,int> ma; int n,x,num[N],f[N],ans,i,j; int main() { read(n); for (i=1;i<=n;++i) read(x),ma[x]=i; for (i=1;i<=n;++i) read(x),num[i]=ma[x]; for (i=1;i<=n;++i) { f[i]=1; for (j=1;j<i;++j) if (num[j]<num[i]) f[i]=max(f[i],f[j]+1),ans=max(ans,f[i]); } printf("%d",ans); return 0; }

      然后优化。方法有两种——二分或树状数组。

      个人还是感觉二分的简单些(因为不会打树状数组的版本)

      用top表示最长不下降子序列的长度;表示用f[i]表示i长度的结尾元素的值。

      仔细观察一下,发现他们满足f[1]<=f[2]<=f[3]……

      然后就可以进行二分优化了

      CODE(常数还挺小)

    #include<cstdio>
    #include<map>
    using namespace std;
    const int N=100005;
    map <int,int> ma;
    int n,x,num[N],f[N],i,top; 
    inline void read(int &x)
    {
        x=0; char ch=getchar(); 
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    }
    inline int max(int a,int b) { return a>b?a:b; }
    inline int find(int x)
    {
        int left=1,right=top,res=0;
        while (left<=right)
        {
            int mid=left+right>>1;
            if (f[mid]<x) res=mid,left=mid+1; else right=mid-1;
        }
        return res;
    }
    int main()
    {
        read(n);
        for (i=1;i<=n;++i)
        read(x),ma[x]=i;
        for (i=1;i<=n;++i)
        read(x),num[i]=ma[x];
        for (i=1;i<=n;++i)
        {
            if (!top) { f[++top]=num[i]; continue; } else
            {
                if (num[i]<f[1]) f[1]=num[i];
                int k=find(num[i]);
                top=max(top,k+1);
                f[k+1]=num[i];
            }
        }
        printf("%d",top);
        return 0;
    }
  • 相关阅读:
    php数组
    php 函数
    数据库操作
    PHP基础
    mysql常用函数
    10.25 (下午) 开课一个月零二十一天(抽象)
    10.25 (上午) 开课一个月零二十一天 (继承多态)
    10.24 (下午) 开课一个月零二十天 (封装)
    10.24 (上午) 开课一个月零二十天 (面向对象)
    10.23 开课一个月零十九天 (PHP数组)
  • 原文地址:https://www.cnblogs.com/cjjsb/p/7941823.html
Copyright © 2011-2022 走看看