UVA 10635 Prince and Princess

题意就是给你两个自身不会有重复元素的数列,求最长公共子序列,O(nlogn)。

去年(?)做过一遍的题现在想想还是很巧妙。

想一想,枚举B的数B[i],看它在A的哪里(丢进桶里维护)。如果有,怎么计算它的答案。

如果有的话,对于一个B[j](j<i),可以转移到它,就是要有:

即找到一个桶的前缀最大值,并进行单点修改,且只会修改一次,且只会增加。

这个就可以用值域树状数组/值域线段树做了。

相当于一个映射后的最长上升子序列,但我每次写这个东西也是用的值域树状数组/值域线段树……懒得想二分。

最重要的性质就是不会有重复的元素,因为有重桶就不能用了。

写起来也很舒服的。

#include    <iostream>
#include    <cstdio>
#include    <cstdlib>
#include    <algorithm>
#include    <vector>
#include    <cstring>
#include    <queue>
#include    <complex>
#include    <stack>
#define LL long long int
#define dob double
#define lb(x) (x&-x)
#define FILE "10635"
using namespace std;

const int N = 70010;
int n,p,q,bin[N],T[N],Ans;

inline int gi(){
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}

inline int query(int x,int res=0){
  for(;x;x-=lb(x))res=max(res,T[x]);
  return res;
}

inline void update(int x,int val){
  for(;x<=n*n;x+=lb(x))T[x]=max(T[x],val);
}

inline void solve(){
  n=gi();p=gi()+1;q=gi()+1;Ans=0;
  memset(bin,0,sizeof(bin));memset(T,0,sizeof(T));
  for(int i=1;i<=p;++i)bin[gi()]=i;
  for(int i=1;i<=q;++i){
    int y=bin[gi()];if(!y)continue;
    int v=query(y)+1;if(v>Ans)Ans=v;
    update(y,v);
  }
  printf("%d
",Ans);
}

int main()
{
  freopen(FILE".in","r",stdin);
  freopen(FILE".out","w",stdout);
  int Case=gi();
  for(int t=1;t<=Case;++t)
    printf("Case %d: ",t),solve();
  fclose(stdin);fclose(stdout);
  return 0;
}
Prince and Princess
原文地址:https://www.cnblogs.com/fenghaoran/p/7655142.html