【模板】加强版最长公共子序列/子串

其实也不是模板啦...........

原理

  • 求最长不下降序列是有nlog{n}算法的
  • 数据离散化的应用

实现

  • 离散化,记\(f(x)\)是由母串的值到母串下标的映射,令所有模式串的值 \(x=f(x)\)
  • 显然母串的下标是严格递增的,那么找最长公共序列就变成了找最长不上升序列, \(O(nlog{n})\)解决...
  • 同理,找最长公共子串就是找最长的\(f(pos)=f(pos-1)+1\)的序列了,\(O(n)\)扫描一遍解决...

记有m个模式串 , 复杂度\(O(mnlog{n})\),注意常数,跑\(10^6\)要两秒多,同时也要注意边界。

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<vector>
#include<set>
#include<map>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<ctime>

using namespace std;


#define TMP template < class ins >
#define endl '\n'
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;t++)
#define ERP(t,a) for(register int t=head[(a)];t;t=e[t].nx)
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;t--)
typedef long long ll;

TMP inline ins qr(ins tag){
    char c=getchar();
    ins x=0;
    int q=0;
    while(c<48||c>57)
    q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)
    x=x*10+c-48,c=getchar();
    return q==-1?-x:x;
}

#define midd register int mid=(lb+rb)>>1
const int maxn=100000+15;
int sav[maxn];
int cnt;
int sttd[maxn];
int in[maxn];
int par[105][maxn];
int tk;
int n,m;
int ans1,ans2;
#define more(a,b) (a)=(a)>(b)?(a):(b)
int stk[maxn];
int top;

inline int lisan(int x){
    int lb=1,rb=n;
    do{
    midd;
    if(sav[mid]<=x)
        lb=mid+1;
    else
        rb=mid-1;
    }while(lb<=rb);
    if(sav[rb]!=x)
    return -1;
    return in[rb];
}


inline int pre(int x){
    int lb=1,rb=n;
    do{
    midd;
    if(sav[mid]<=x)
        lb=mid+1;
    else
        rb=mid-1;
    }while(lb<=rb);
    return rb;
}


inline int lbound(int lb,int rb,int *p,int x){
    do{
    midd;
    if(p[mid]<x)
        lb=mid+1;
    else
        rb=mid-1;
    }while(lb<=rb);
    return lb;
}


inline int zixulie(int *p){
    int ret=0;
    stk[0]=0;
    RP(t,1,n){
    if(p[t]==-1)
        continue;
    if(p[t]>stk[ret])
        stk[++ret]=p[t];
    else
        stk[lbound(1,ret,stk,p[t])]=p[t];
    }
    return ret;
}


inline int zichuan(int *p){
    int ret=0;
    int sav=0;
    p[0]=-1;
    RP(t,1,n){
    if(p[t]==-1){
        sav=0;
        continue;
    }
    if(p[t]==p[t-1]+1)
        ++sav;
    else
        more(ret,sav+1),sav=0;
    }
    if(sav)
    more(ret,sav+1);
    return ret;
}


inline void eff(){
    int t1,t2;
    RP(t,1,m){
    t1=zixulie(par[t]);
    t2=zichuan(par[t]);
    more(ans1,t1);
    more(ans2,t2);
    }
    cout<<ans1<<endl<<ans2<<endl;
}


inline void init(){
    n=qr(1);
    m=qr(1);
    RP(t,1,n)
    sav[t]=sttd[t]=qr(1);
    sort(sav+1,sav+n+1);
    RP(t,1,n)
    in[pre(sttd[t])]=t;
    RP(t0,1,m){
    int* p=par[t0];
    RP(t,1,n)
        p[t]=lisan(qr(1));
    }
}

int main(){
    init();
    eff();
    return 0;
}

一百五十行...要是考场上坚持这个想法刚就好了,我还以为这么简单肯定很多人切,原来没有几个.....不过\(NOIP_{2018}.RP++\)成功....

猜你喜欢

转载自www.cnblogs.com/winlere/p/10307955.html