zoj 2319 Beautiful People 【最长上升序列】
2017-04-19 10:49
323 查看
题意: 给你n个人,每个人有两种权值。然后排队,让你找到最长的队伍人数及分别是哪些人(任意输出一组)。
排队方法为,每个位置的人的两个权值都完全大于前一个人的两个权值。
题解: 最长上升子序列。
两个模板,n^2 and nlogn
显然 n^2 直接结果就是对的,但是超时。(听说用线段树维护能降低到nlogn。)
nlogn 直接结果不对,但是不超时。
而我当时却没写出来。
首先有nlogn的两种解法,
1. 优先权值x 排序,跑一边, 再优先权值y跑一边,比较最大值,输出, 这样相当于2*n*logn; (orz 这确实是个好做法)
2. 直接优先x 排序,dp【i】记录的是该点排序后的下标,最后逆着跑出来。就是最优解。
下面第二种解法ac代码:
#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100110;
int T,n;
struct node{
int x,y,nu;
}a[maxn],d[maxn];
int cmp(node aa,node bb){
if(aa.x==bb.x) return aa.y>bb.y;
return aa.x<bb.x;
}
int pre[maxn];
int q[maxn];
int dp[maxn];
int main(){
scanf("%d",&T);
while(T--){
memset(pre,0,sizeof(pre));
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d %d",&a[i].x,&a[i].y);
a[i].nu=i;
}
sort(a+1,a+n+1,cmp);
int len=0;
dp[++len]=1;
for(int i=2;i<=n;++i){
if(a[dp[len]].y<a[i].y) dp[++len]=i,pre[i]=dp[len-1];
else{
int l=1,r=len;
while(l<=r){
int mid=(l+r)/2;
if(a[dp[mid]].y>=a[i].y) r=mid-1;
else l=mid+1;
}
dp[l]=i;
pre[i]=dp[l-1];
}
}
int st=0,t=dp[len];
printf("%d\n",len);
for(int i=len,j=dp[len];i>=1;j=pre[j],--i) q[++st]=a[j].nu;
for(int i=1;i<st;++i) printf("%d ",q[i]);
printf("%d\n",q[st]);
}
return 0;
}
排队方法为,每个位置的人的两个权值都完全大于前一个人的两个权值。
题解: 最长上升子序列。
两个模板,n^2 and nlogn
显然 n^2 直接结果就是对的,但是超时。(听说用线段树维护能降低到nlogn。)
nlogn 直接结果不对,但是不超时。
而我当时却没写出来。
首先有nlogn的两种解法,
1. 优先权值x 排序,跑一边, 再优先权值y跑一边,比较最大值,输出, 这样相当于2*n*logn; (orz 这确实是个好做法)
2. 直接优先x 排序,dp【i】记录的是该点排序后的下标,最后逆着跑出来。就是最优解。
下面第二种解法ac代码:
#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100110;
int T,n;
struct node{
int x,y,nu;
}a[maxn],d[maxn];
int cmp(node aa,node bb){
if(aa.x==bb.x) return aa.y>bb.y;
return aa.x<bb.x;
}
int pre[maxn];
int q[maxn];
int dp[maxn];
int main(){
scanf("%d",&T);
while(T--){
memset(pre,0,sizeof(pre));
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d %d",&a[i].x,&a[i].y);
a[i].nu=i;
}
sort(a+1,a+n+1,cmp);
int len=0;
dp[++len]=1;
for(int i=2;i<=n;++i){
if(a[dp[len]].y<a[i].y) dp[++len]=i,pre[i]=dp[len-1];
else{
int l=1,r=len;
while(l<=r){
int mid=(l+r)/2;
if(a[dp[mid]].y>=a[i].y) r=mid-1;
else l=mid+1;
}
dp[l]=i;
pre[i]=dp[l-1];
}
}
int st=0,t=dp[len];
printf("%d\n",len);
for(int i=len,j=dp[len];i>=1;j=pre[j],--i) q[++st]=a[j].nu;
for(int i=1;i<st;++i) printf("%d ",q[i]);
printf("%d\n",q[st]);
}
return 0;
}
相关文章推荐
- ZOJ 2319 最长上升子序列并输出组成该序列的元素编号
- ZOJ 2319【二维最长递增子序列】
- ZOJ - 2319 Beautiful People 【最长单调递增子序列变形】
- (LCIS)最长公共上升子序列 ZOJ 2432
- zoj 2136 Longest Ordered Subsequence 最长上升子序列 新思路
- zoj 2136 Longest Ordered Subsequence(最长上升子序列,第二次写 = =)
- 【第四场省赛组队赛训练补题】ZOJ - 2319 Beautiful People (最长单调递增子序列 O(nlogn) )
- zoj1986,poj1631,最长上升子序列,复杂度O(n*logn)
- zoj 2136 Longest Ordered Subsequence 最长上升子序列 新思路
- zoj 2432 Greatest Common Increasing Subsequence(最长公共上升子序列)
- 最长上升子序列-LintCode
- HDU1423 最长上升公共子序列
- LIS - 最长上升子序列 (二分优化)
- “最长上升子序列,最大连续子序列和,最长公共子串”的Java实现
- 最长上升自序列
- POJ 2757 最长上升子序列 解题报告
- 最长上升子序列(LIS)和最长下降子序列(LDS)
- hdu1950Bridging signals(求最长上升自序列nlogn算法)
- 最长公共子上升序列
- UVA - 10599 Robots(II)(最长上升自序列)