其实也不是模板啦...........
原理
- 求最长不下降序列是有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 '
'
#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++)成功....