您的位置:首页 > 运维架构

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 the
club) 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 and
Bi 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: