ACdream 1216 Beautiful People(二路最长上升子序列 O(nlogn) )
2015-08-27 19:44
483 查看
Beautiful People
Special Judge Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB(Java/Others)
Submit Statistic Next
Problem
Problem Description
The most prestigious sports club in one city has exactly N members. Each of its members is strong and beautiful. More precisely, i-th member of this club (members being numbered by the time they entered theclub) has strength Si and beauty Bi. Since this is a very prestigious club, its members are very rich and therefore extraordinary people, so they often extremely hate each other. Strictly speaking, i-th member of the club Mr X hates j-th member of the club
Mr Y if Si <= Sj and Bi >= Bj or if Si >= Sj and Bi <= Bj (if both properties of Mr X are greater then corresponding properties of Mr Y, he doesn't even notice him, on the other hand, if both of his properties are less, he respects Mr Y very much).
To celebrate a new 2003 year, the administration of the club is planning to organize a party. However they are afraid that if two people who hate each other would simultaneouly attend the party, after a drink
or two they would start a fight. So no two people who hate each other should be invited. On the other hand, to keep the club prestige at the apropriate level, administration wants to invite as many people as possible.
Being the only one among administration who is not afraid of touching a computer, you are to write a program which would find out whom to invite to the party.
Input
The first line of the input file contains integer N — the number of members of the club. (2 ≤ N ≤ 100 000). Next N lines contain two numbers each — Si andBi respectively (1 ≤ Si, Bi ≤
109).
Output
On the first line of the output file print the maximum number of the people that can be invited to the party. On the second line output N integers — numbers of members to be invited in arbitrary order. If several solutions exist, output any one.
Sample Input
4 1 1 1 2 2 1 2 2
Sample Output
2 1 4
题目大意:
从n个人中挑选出若干人,使得这些人中的任何一个人的两种属性同时大于或同时小于其他人。输出最多能挑选出的人的个数和编号。
解题思路:
问题可以化成从这n个人中挑选出若干人,使得他们的两种属性都上升。所以题目就变成了二路最长上升子序列。
首先先按照s值为第一关键字(升序),b值为第二关键字(降序)的方式排序。这样排序之后我们可以保证s值一定是升序,所以只需要求出b值的最长上升子序列即为最终答案。b值为什么要按照降序排列呢?因为这样可以最大限度的使得第i个人的b值与经过挑选之后的第i个人的前一个人的b值相差最大。
题目的n很大,所以不能使用LIS朴素的O(n^2)的方法,要用O(nlog(n))。同时O(nlog(n))的算法中的dp数组刚好可以记录第i个人之前(包含i)的LIS。最后逆序遍历输出编号。
参考代码:
#include<bits/stdc++.h> using namespace std; const int INF=0x3f3f3f3f; const int MAXN=1e6+50; struct person { int s,b,id; bool operator<(const person& t)const { if(s==t.s) return b>t.b; return s<t.s; } }p[MAXN]; int n,dp[MAXN],LIS[MAXN]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE while(scanf("%d",&n)!=EOF) { memset(dp,INF,sizeof(dp)); memset(LIS,0,sizeof(LIS)); int len=1,ans=1; for(int i=1;i<=n;i++) { scanf("%d%d",&p[i].s,&p[i].b); p[i].id=i; } sort(p+1,p+1+n); for(int i=1;i<=n;i++) { int tid=lower_bound(dp+1,dp+1+len,p[i].b)-dp; if(tid==len) len++; dp[tid]=p[i].b; LIS[i]=tid; ans=max(ans,tid); } printf("%d\n",ans); for(int i=n;i>=1;i--) { if(LIS[i]==ans) { printf("%d",p[i].id); if(len!=1) printf(" "); ans--; } } puts(""); } return 0; }
相关文章推荐
- Linux内核工程导论——Linux的启动
- centos镜像作为本地源的yum安装
- 数论(Lucas定理) HDOJ 4349 Xiao Ming's Hope
- Linux学习日记--基础命令(8)--算数运算,条件测试
- GDT、GDTR、LDT、LDTR的理解 [zz]
- 【转】在CentOS上安装tomcat
- linux中root密码忘了怎么办?
- GCD和NSOperation多线程技术
- 【转】CentOS上安装 jdk:rpm安装和源码安装
- Linux用户和用户组以及相关命令(下)
- CentOS6.7 用vmware设置共享,执行mount -t vmhgfs 报错no such device解决办法
- Linux系统管理-系统资源查看
- Linux 删除文件夹和文件的命令
- 理解RESTful架构
- 使用logrotate配置Nginx日志轮替
- 从零单排Opencv---新旧版本函数变化
- linux开机启动步骤
- Linux学习日记--基础命令(7)--bash中的变量,配置文件
- CentOS学习3_CentOS6.5下安装Eclipse
- POJ 3258 River Hopscotch(二分法)