题目大意:某个大学有个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. C# 中的常用正则表达式大全

       这是从网上找来的,收藏一下备用,用到之处可以节省不少时间哦! 只能输入数字: "^[0-9]*$" . 只能输入n位的数字:"^\d{n}$". 只能输入 ...

  2. ckeditor的使用与验证

    1.使id=id的textArea变为富文本编辑框 function inittextarea(id) {  CKEDITOR.replace(id,{         width:'600px',  ...

  3. 京东UED招聘web前端开发工程师(中/高级)

    工作职责: 负责前端界面的构建和各类交互设计与实现: 前端样式和脚本的模块设计及优化: 协同后台开发人员完成项目: 负责新产品开发线前端工作(新产品.垂直站.移动端 .后端系统),可根据个人喜好及特长 ...

  4. 使用notepad++学习python爬虫,print网页中文乱码问题

    今天学习使用python爬虫的时候发现爬到的网页中文会乱码,一直网上搜索解决办法,一个一个试验过去,发现还是乱码,然后我就开始使用其它方法测试,用python自带的编辑器打开是正常的,发现是notep ...

  5. knockout简单实用教程2

    在上一篇文章中简单了介绍了下什么ko(后文中都已ko来代替knockout.js)和一些简单的ko的使用方法下面我将介绍在实际的项目中常用到的几种绑定方式和方法. 在开始之前先拿一个dome来回顾下k ...

  6. ORA-01653:表无法通过64(在表空间USERS中)扩展

    问题描述:oracle插入数据时显示ORA-01653 表无法通过64(在表空间USERS中)扩展 原因:  oracle  表空间满了,需要扩展 截图: 解决方法: 1.首先查下表空间 select ...

  7. Nginx 变量漫谈(八)

    与 $arg_XXX 类似,我们在 (二) 中提到过的内建变量 $cookie_XXX 变量也会在名为 XXX 的 cookie 不存在时返回特殊值“没找到”:     location /test  ...

  8. 仿制的ActivityIndicatorView

    仿制Github上CSS3效果制作的几个简单的ActivityIndicator,复习一下IOS动画操作. 原效果连接:https://github.com/tobiasahlin/SpinKit 代 ...

  9. Inno Setup 插件 CallbackCtrl V1.1 (回调函数插件)

    原文 http://restools.hanzify.org/article.asp?id=101 VC 重现 InnoCallback 的功能. Version 1.1修正在某些 Windows 平 ...

  10. 如何诊断crs 安装时 root.sh 脚本执行错误

    troubleshooting root.sh problem ------*for 10g and 11.1 1.查证公网,私网的节点名是可以互相ping通的 2.---查证OCR/Voting 文 ...