ACdream 1216 Beautiful People 二路最长上升子序列

来源:互联网 发布:win10提速 优化 编辑:程序博客网 时间:2024/06/05 15:06

题目描述:

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 — S i and B i 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

41 11 22 12 2

Sample Output

21 4

题目分析:

有n个人,他们分别有两个值a和b,创建一个序列x,保证 xai < xaj, xbi < xbj (i < j)。输出序列中最多的人数以及他们的序号。
这题是一道最长上升子序列的题目(我没有看出来~~),将这些人按照a升序排列,若a相同,按b降序排列。(这样保证对b进行的运算是满足a的最长上升子序列 不然会造成b是递增的子序列,而a值相等,就不满足题意了)
然后就是对b进行LIS算法,二分(lower_bound)求位置,将最长的序列求出来,并记录他们的原序号。

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>using namespace std;const int MAXN=100005;const int INF=0x3f3f3f3f;struct node{    int a,b;    int number;};bool cmp(node x,node y){    if (x.a==y.a)    {        return x.b>y.b;    }    return x.a<y.a;}node seq[MAXN];int dp[MAXN];int mark[MAXN];int n;int main(){    while(scanf("%d",&n)!=-1)    {        for(int i=1; i<=n; i++)        {            scanf("%d%d",&seq[i].a,&seq[i].b);            seq[i].number=i;        }        sort(seq+1,seq+n+1,cmp);        memset(dp,INF,sizeof(dp));        int ans=0;        int len=1;        for(int i=1; i<=n; i++)        {            int k=lower_bound(dp+1,dp+1+n,seq[i].b)-dp; //二分法也可以实现            if (k==len)            {                len++;            }            dp[k]=seq[i].b;            mark[i]=k;//mark值记录的是以他们为终点的子序列长度            ans=max(k,ans);        }        printf("%d\n",ans);//        for(int i=1; i<=n; i++)//        {//            printf("%d ",mark[i]);//        }//        printf("\n");        for(int i=n; i>=1; i--)        {            if (mark[i]==ans)            {                printf("%d ",seq[i].number);                ans--;            }        }        printf("\n");        //这样输出的编号顺序是倒置的 不过因为题目允许,所以就这样了 如果要顺序输出编号,可以使用vector容器将这些人的编号存入    }    return 0;}

附上LIS详解:
http://www.cnblogs.com/mycapple/archive/2012/08/22/2651461.html

0 0
原创粉丝点击