hdu3525
题目大意:某个大学有个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,搓啊!!!!)
最后答案对应的那个目标串中每个匹配的串中每个元素在源串肯定都是有一个下标。
如样例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的更多相关文章
随机推荐
- 查看IIS进程id
Windows 2003 cscript C:\windows\system32\iisapp.vbs -a Windows 2008 C:\windows\system32\inetsrv\appc ...
- iOS 事件处理机制与图像渲染过程
Peter在开发公众号功能时触发了一个bug,导致群发错误.对此我们深表歉意,并果断开除了Peter.以下交回给正文时间: iOS 事件处理机制与图像渲染过程 iOS RunLoop都干了什么 iOS ...
- sqlite在c++中的使用方法
1.需要下载的文件 http://pan.baidu.com/s/1c06NpzM 2.执行文件shell的编译 3.在c++中如何使用 #include <stdio.h> # ...
- oracle数据库管理--用户管理
一.oracle数据库用户管理 1.sys和system用户区别 (1)存储的数据的重要性不同: sys所有oracle的数据字典的基表和视图都存放在sys用户中,这些基表和视图对于or ...
- 关于serialVersionUID的说明
1.为什么要使用serialVersionUID (1)对于实现了Serializable接口的类,可以将其序列化输出至磁盘文件中,同时会将其serialVersionUID输出到文件中. (2)然后 ...
- 使用jsonp实现ajax跨域请求
Jsonp(JSON with Padding)是资料格式 json 的一种“使用模式”,可以让网页从别的网域获取资料. 由于同源策略,一般来说位于 server1.example.com 的网页无法 ...
- OpenLayers 3加载本地Google切片地图
OpenLayers 提供了ol.source.XYZ 接口用以加载切片地图. 本地切片地图是用地图切片下载器下载的Google道路图层,由于软件未激活,所以每张切片地图上都有软件作者的联系方式,请 ...
- fzu 1753 Another Easy Problem
本题题意为求 t (t<150) 个 c (n,m) (1<=m<=n<=100000)的最大公因子: 本题的难点为优化.主要有两个优化重点.一是每次对单个素因子进行处理,优 ...
- SqlServer取得一个月的所有有日期
SqlServer的自定义函数可以分为三类但我只用过上面两类,可以称作标量函数和表值函数,区别只是返回数据的类型,表值函数返回的是一个虚拟表 SqlServer的函数在这里 因某种需求我写了一个这样的 ...
- tomcat------https单向认证和双向认证
一.https分为单向认证和双向认证: 单向认证就是说,只有客户端使用ssl时对服务器端的证书进行认证,也就是说,客户端在请求建立之前,服务器端会向客户端发送一个证书,一般情况下,这种证书都是由自己 ...