zoukankan      html  css  js  c++  java
  • ZOJ3519-Beautiful People:最长上升子序列的变形

    Beautiful People

    Special JudgeTime Limit: 10000/5000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others)

    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 Brespectively (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

    Source

    Andrew Stankevich Contest 1
     
     
     
    算法:最长上升子序列nlogn的解法(详情可以参见大白书P62),本题有一个不同的地方是,2个值都是严格递增(设为x,y),所以可根据x的值从小到大排序,这时我们从左往右只需考虑y的值因为x的值一定是递增的; 当x相同时根据y的值从大到小排序,为什么y要递减呢?因为当x相等时如果y为递增的话,那么选出的方案中就会将x相等的几个people都包含进去,显然是错的。然后我们就可以进行DP了,cnt[i]表示以第i个people结尾的最长上升子序列的长度,d[i]表示最长上升子序列长度为i时子序列末尾的最小y值(详见代码)。
    本题还需要输出其中一种方案,我们只需根据DP得到的状态回溯输出就OK了。
     
     
     1 #include <iostream>
     2 #include <memory.h>
     3 #include <algorithm>
     4 #include <stdio.h>
     5 using namespace std;
     6 #define INF 1000000000
     7 #define MAXN 100010
     8 class CT
     9 {
    10 public:
    11     int x,y,num;
    12     bool operator <(const CT &c2)const
    13     {
    14         if(x!=c2.x)
    15             return x<c2.x;
    16         return y>c2.y;
    17     }
    18 };
    19 
    20 CT a[MAXN];
    21 int d[MAXN];
    22 int cnt[MAXN]={0};
    23 int fa[MAXN];
    24 
    25 int main()
    26 {
    27     #ifndef ONLINE_JUDGE
    28     freopen("in.txt","r",stdin);
    29     #endif
    30     int n;
    31     while(~scanf("%d",&n))
    32     {
    33         for(int i=1;i<=n;i++)
    34         {
    35             scanf("%d %d",&a[i].x,&a[i].y);
    36             a[i].num=i;
    37         }
    38         sort(a+1,a+1+n);
    39 
    40         d[0]=0;
    41         fill_n(d+1,n+5,INF);
    42         memset(cnt,0,sizeof cnt);
    43         memset(fa,-1,sizeof fa);
    44         int ans=0;
    45 
    46         for(int i=1;i<=n;i++)
    47         {
    48             int low=lower_bound(d,d+i,a[i].y)-d-1;
    49             cnt[i]=low+1;
    50             ans=max(ans,cnt[i]);
    51             d[low+1]=a[i].y;
    52         }
    53 
    54         printf("%d
    ",ans);
    55         int u;
    56         for(int i=n;i>=1;i--)
    57             if(cnt[i]==ans)
    58             {
    59                 u=i;
    60                 break;
    61             }
    62 
    63         printf("%d",a[u].num);
    64         int pre=u;
    65         for(int i=u-1;i>=1;i--)
    66         {
    67             if(a[i].y<a[pre].y && cnt[i]==cnt[pre]-1)
    68             {
    69                 printf(" %d",a[i].num);
    70                 pre=i;
    71             }
    72         }
    73         printf("
    ");
    74     }
    75     return 0;
    76 }
  • 相关阅读:
    洛谷.3254.圆桌问题(最大流ISAP)
    BZOJ.2639.矩形计算(二维莫队)
    BZOJ.2724.[Violet 6]蒲公英(静态分块)
    BZOJ.4241.历史研究(回滚莫队 分块)
    BZOJ.4542.[HNOI2016]大数(莫队)
    SPOJ.COT2 Count on a tree II(树上莫队)
    BZOJ.3757.苹果树(树上莫队)
    洛谷.2325.[SCOI2005]王室联邦(贪心)
    BZOJ.1299.[LLH邀请赛]巧克力棒(博弈论 Nim)
    HDU.2516.取石子游戏(博弈论 Fibonacci Nim)
  • 原文地址:https://www.cnblogs.com/oneshot/p/4003592.html
Copyright © 2011-2022 走看看