很有意思的一道题啊。
求两个序列的最大公共子序列。保证每个序列中含有1-n各5个。
如果直接LCS显然是TLE的。该题与普通的LCS不同的是每个序列中含有1-n各5个。
考虑LCS的经典DP方程。dp[i][j]=dp[i-1][j-1]+1.(a[i]==b[j])。 dp[i][j]=max(dp[i-1][j],dp[i][j-1]).(a[i]!=b[j])。
如果换个角度看看。令dp[i][j]表示a序列以i结尾,b序列到j的最大公共子序列长度。
则有dp[i][j]=max(dp[k][j])+1.(a[i]==b[j]&&k<i)。 dp[i][j]=max(dp[i][k]).(a[i]!=b[j]&&k<j).
如果从b序列从左向右更新状态的话。第一个转移就是求前缀最大值。第二个转移实际就是不变。
因此维护一个线段树即可。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-9 # define MOD 1000000000 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=20005; //Code begin... int a[N*5], b[N*5], vis[N][6], cnt[N], seg[N*20]; void push_up(int p){seg[p]=max(seg[p<<1],seg[p<<1|1]);} int query(int p, int l, int r, int R){ if (R<l) return 0; if (R>=r) return seg[p]; int mid=(l+r)>>1; return max(query(lch,R),query(rch,R)); } void update(int p, int l, int r, int L, int val){ if (L>r||L<l) return ; if (L==l&&L==r) seg[p]=max(seg[p],val); else { int mid=(l+r)>>1; update(lch,L,val); update(rch,L,val); push_up(p); } } int main () { int n; scanf("%d",&n); FOR(i,1,n*5) { scanf("%d",a+i); vis[a[i]][++cnt[a[i]]]=i; } FOR(i,1,n*5) { scanf("%d",b+i); for (int j=5; j>=1; --j) { int tmp=query(1,1,n*5,vis[b[i]][j]-1)+1; update(1,1,n*5,vis[b[i]][j],tmp); } } printf("%d\n",query(1,1,n*5,n*5)); return 0; }