题目大意:某个大学有个2个校区,此大学有n(1<=n<=10000)个运动员,这n个运动员在每个校区都挑选了m(1<=m<=10)个拉拉队。现在每个校区(A/B)中,这m*n个拉拉队按照登记顺序说出自己支持的运动员编号和自己想排在那个位置(输入顺序,m*n*2个数字),排成一列。如果冲突则按照先来后到的顺序依次往后排。求按照A/B的两个拉拉队员站的位置,用他们支持的运动员编号形成的两个序列的最长公共子序列。这道题给4s,20组样例,运算复杂度允许10^7。

思路还是比较明确的。知识点:稀疏序列的匹配,最长上升子序列

第一步:预处理求A/B串。

这个比较好办,如果A(B)列中某君L想在第X个位置:选第X个位置给它,如果X没人占;二分枚举Y(Y>X),X到Y之间空位 = F(Y)-F(X)+1 {F(X)表示1到X之间站的人数},如果X有人站。(树状数组+二分)

第二步:比较A/B。

(最初想法,现在令f(x,y)表示A的前x个数字与B中前y个数字的匹配数,对x从前到后枚举,找B个匹配的y(最多m个),那么f(x,y')=max(f(x,y'),f(x,y-1)+1) {y<=y'<=N=m*n},这不很典型的区间置数问题了吗?solution就很容易想到:线段树。可惜TLE,搓啊!!!!)

首先感谢网上某位大神和我的队友:wonderzy.

最后答案对应的那个目标串中每个匹配的串中每个元素在源串肯定都是有一个下标。

如样例A:3 3 1 1 2 2, B: 3 2 3 1 2 1,最后答案是4,对应着3 3 1 1/3 3 1 2。

其实如果这么A中每一个元素可选在B中的位置(3 1) (3 1) (6 4) (6 4) (5 2) (5 2)。A中每个元素就对应着一个括号,标识着它的可选方案,当然这个元素也可以不选。

这样,结果不就是正好是3 1 3 1 6 4 6 4 5 2 5 2这个串最长上升子序列长度吗?

贴个代码

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=;
struct position{
int id,atx;
}pos[maxn];
int S[maxn*],*pid,N;
#define lowest(x) ((-x)&x)
int sumDown(int x){
int ret=;
while(x>){
ret += S[x];
x -= lowest(x);
}
return ret;
}
void addUp(int x,int id){
pid[x]=id;
while(x <= N){
S[x]++;
x+=lowest(x);
}
}
int findPos(int sf,int left,int right){
int x0=left-;
while(left < right){
int x=(left+right)>>;
int fx=sumDown(x);
if(x-x0 > fx-sf) right=x;
else left=x+;
}
return left;
}
void setOrder(int *A,int m,int n){
pid=A; N=m*n*;
for(int i=N;i>=;i--) S[i]=pid[i]=;
int n2=n*m;
for(int i=;i<n2;i++){
int px=pos[i].atx;
if(!pid[px]) addUp(px,pos[i].id);
else {
int sf=sumDown(px);
px=findPos(sf,px+,N);
addUp(px,pos[i].id);
}
}
int p1=,p2=;
while(p1<n2){
if(pid[p2]) pid[++p1]=pid[p2];
p2++;
}
}
int A[maxn*],B[maxn*],C[maxn*];
int pre[maxn*],head[maxn*];
int gao_LIS(int a[],int len){ //最长公共子序列
int ret=;
int b[maxn];
b[ret++]=a[];
for(int i=;i<len;i++){
int x=lower_bound(b,b+ret,a[i])-b;
if(x==ret){
b[ret++]=a[i];
}else{
b[x]=a[i];
}
}
return ret;
}
int main()
{
int cases; cin>>cases;
int n,m;
for(int cas=;cas<=cases;cas++){
scanf("%d%d",&n,&m);
int n2=m*n;
for(int i=;i<n2;i++) scanf("%d%d",&pos[i].id,&pos[i].atx);
setOrder(A,m,n);
for(int i=;i<n2;i++) scanf("%d%d",&pos[i].id,&pos[i].atx);
setOrder(B,m,n);
//for(int i=1;i<=n2;i++) printf("%d ",A[i]); cout<<endl;
//for(int i=1;i<=n2;i++) printf("%d ",B[i]); cout<<endl;
/******************************/
for(int i=m*n;i>=;i--) head[i]=;
for(int i=;i<=n2;i++)
pre[i]=head[A[i]], head[A[i]]=i;
int idx=;
for(int i=;i<=n2;i++)
for(int j=head[B[i]];j;j=pre[j])
C[idx++]=j;
//for(int i=0;i<idx;i++) cout<<C[i]<<" "; cout<<endl;
printf("Case #%d: %d\n",cas,gao_LIS(C,idx));
/******************************/
}
return ;
}

hdu3525的更多相关文章

随机推荐

  1. 浅谈JavaScript DOM编程艺术读后感和一点总结

    最近工作不是很忙就想想想JavaScript的内部组成和一些要点,就是从这本书开始的.对新手来说还好,简单易懂. 简单终结下我重书中学到的一些要点. 下面都是个人学习的要点提取: 1.给自己预留退路, ...

  2. HttpApplication事件执行顺序(转)

    HttpApplication 类的实例(Global继承自该类)是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的.HttpApplication 类的一个实例在其生存期内被用于处理多个 ...

  3. 【转】关于ios10中ATS的问题

    原文连接:https://onevcat.com/2016/06/ios-10-ats/ WWDC 15 提出的 ATS (App Transport Security) 是 Apple 在推进网络通 ...

  4. 计算UILabel的高度

    //计算文本高度 NSString *lltxt =[[NSString alloc]initWithFormat:@"浏览:%@",[strJson objectForKey:@ ...

  5. Octet string 解析

    百度百科的 ASN.1 http://baike.baidu.com/view/26378.htm 什么是 octet string 结构化字节 怎么解析,这里有微软的解析方法 If the byte ...

  6. R - 一只小蜜蜂...(第二季水)

    Description          有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数.         其中,蜂房的结构如下所示.     ...

  7. 从汇编看c++初始化列表初始化成员变量

    简略来说,编译器会对初始化列表按照成员变量的声明顺序重新一一排序,安插到构造函数中进行初始化操作,而且这些初始化操作在构造函数里面用户自己定义的任何代码之前. 下面是c++源码: class X { ...

  8. mysql三张表关联查询

    三张表,需要得到的数据是标红色部分的.sql如下: select a.uid,a.uname,a.upsw,a.urealname,a.utel,a.uremark, b.rid,b.rname,b. ...

  9. %hd %d %ld %u ......

    %d 有符号10进制整数 %ld 长整型 %hd短整型%md,m指定的是输出字段的宽度,默认左补空格, 如果数据的位数小于m,则左端补以空格,若大于m,则 按实际位数输出,如: printf(&quo ...

  10. 过河问题--nyoj题目47

    过河问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:5   描述 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话,大家是无论如何也不敢过桥去的 ...