zoj 2319 Beautiful People

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1319

题目大意:就是求最长递增子序列,并输出位置。。。。

思路:先把s进行升序排列,然后把b按降序排列,最后把找出b的最长递增子序列。。。。

先给两个最长递增子序列的模板:了解更多轻点这儿。。。。。。

时间复杂度:O(log(n*n))

unsigned int LISS(const int array[], size_t length, int result[])
{
    unsigned int i, j, k, max;

    //变长数组参数,C99新特性,用于记录当前各元素作为最大元素的最长递增序列长度
    unsigned int liss[length];

    //前驱元素数组,记录当前以该元素作为最大元素的递增序列中该元素的前驱节点,用于打印序列用
    unsigned int pre[length];

    for(i = 0; i < length; ++i)
    {
        liss[i] = 1;
        pre[i] = i;
    }

    for(i = 1, max = 1, k = 0; i < length; ++i)
    {
        //找到以array[i]为最末元素的最长递增子序列
        for(j = 0; j < i; ++j)
        {
            //如果要求非递减子序列只需将array[j] < array[i]改成<=,
            //如果要求递减子序列只需改为>
            if(array[j] < array[i] && liss[j] + 1> liss[i])
            {
                liss[i] = liss[j] + 1;
                pre[i] = j;

                //得到当前最长递增子序列的长度,以及该子序列的最末元素的位置
                if(max < liss[i])
                {
                    max = liss[i];
                    k = i;
                }
            }
        }
    }

    //输出序列
    i = max - 1;

    while(pre[k] != k)
    {
        result[i--] = array[k];
        k = pre[k];
    }

    result[i] = array[k];

    return max;
}

时间复杂度:O(nlog(n))

unsigned int LISSEx(const int array[], size_t length, int result[])
{
    unsigned int i, j, k, l, max;

    //栈数组参数,C99新特性,这里的liss数组与上一个函数意义不同,liss[i]记录长度为i + 1
    //递增子序列中最大值最小的子序列的最后一个元素(最大元素)在array中的位置
    unsigned int liss[length];

    //前驱元素数组,用于打印序列
    unsigned int pre[length];

    liss[0] = 0;

    for(i = 0; i < length; ++i)
    {
        pre[i] = i;
    }

    for(i = 1, max = 1; i < length; ++i)
    {
        //找到这样的j使得在满足array[liss[j]] > array[i]条件的所有j中,j最小
        j = 0, k = max - 1;

        while(k - j > 1)
        {
            l = (j + k) / 2;

            if(array[liss[l]] < array[i])
            {
                j = l;
            }
            else
            {
                k = l;
            }
        }

        if(array[liss[j]] < array[i])
        {
            j = k;
        }

        //array[liss[0]]的值也比array[i]大的情况
        if(j == 0)
        {
            //此处必须加等号,防止array中存在多个相等的最小值时,将最小值填充到liss[1]位置
            if(array[liss[0]] >= array[i])
            {
                liss[0] = i;
                continue;
            }
        }

                //array[liss[max -1]]的值比array[i]小的情况
                if(j == max - 1)
        {
            if(array[liss[j]] < array[i])
            {
                pre[i] = liss[j];
                liss[max++] = i;
                continue;
            }
        }

        pre[i] = liss[j - 1];
        liss[j] = i;
    }

    //输出递增子序列
    i = max - 1;
    k = liss[max - 1];

    while(pre[k] != k)
    {
        result[i--] = array[k];
        k = pre[k];
    }

    result[i] = array[k];

    return max;
}

AC code:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>

using namespace std;

struct Node
{
    int s,b,id;  //记录s,b,还有开始的位置
}node[100010];

bool cmp(Node t1,Node t2)
{
    return t1.s<t2.s||(t1.s==t2.s&&t1.b>t2.b);
}

unsigned int LISSEx(const Node array[], size_t length, int result[])
{
    unsigned int i, j, k, l, max;

    //栈数组参数,C99新特性,这里的liss数组与上一个函数意义不同,liss[i]记录长度为i + 1
    //递增子序列中最大值最小的子序列的最后一个元素(最大元素)在array中的位置
    unsigned int liss[length];

    //前驱元素数组,用于打印序列
    unsigned int pre[length];

    liss[0] = 0;

    for(i = 0; i < length; ++i)
    {
        pre[i] = i;
    }

    for(i = 1, max = 1; i < length; ++i)
    {
        //找到这样的j使得在满足array[liss[j]] > array[i]条件的所有j中,j最小
        j = 0, k = max - 1;

        while(k - j > 1)
        {
            l = (j + k) / 2;

            if(array[liss[l]].b < array[i].b)
            {
                j = l;
            }
            else
            {
                k = l;
            }
        }

        if(array[liss[j]].b < array[i].b)
        {
            j = k;
        }

        //array[liss[0]]的值也比array[i]大的情况
        if(j == 0)
        {
            //此处必须加等号,防止array中存在多个相等的最小值时,将最小值填充到liss[1]位置
            if(array[liss[0]].b >= array[i].b)
            {
                liss[0] = i;
                continue;
            }
        }

                //array[liss[max -1]]的值比array[i]小的情况
                if(j == max - 1)
        {
            if(array[liss[j]].b < array[i].b)
            {
                pre[i] = liss[j];
                liss[max++] = i;
                continue;
            }
        }

        pre[i] = liss[j - 1];
        liss[j] = i;
    }

    //输出递增子序列
    i = max - 1;
    k = liss[max - 1];

    while(pre[k] != k)    //记录排序后得到的最长递增子序列的位置
    {
        result[i--] = k;
        k = pre[k];
    }

    result[i] = k;

    return max;
}

int result[100010],array[100010];
int main()
{

    int n,i;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&node[i].s,&node[i].b);
            node[i].id=i+1;
        }
        sort(node,node+n,cmp);
        int len=LISSEx(node,n,result);
        printf("%d\n",len);
        for(i=0;i<len-1;i++)
        {
            printf("%d ",node[result[i]].id);
        }
        printf("%d\n",node[result[i]].id);
    }
    return 0;
}
时间: 2024-10-14 05:11:01

zoj 2319 Beautiful People的相关文章

ZOJ 2850: Beautiful Meadow

ZOJ - 2850 ///@author Sycamore, ZJNU ///@accepted_on 2017-01-19 #include<iostream> using namespace std; bool bl[10][10]; int main() { short M, N; while (cin >> M >> N&&M&&N) { bool b1=true,b2 = false; for (int i = 0; i<

ZOJ 2829 Beautiful Number(睡前一水)

链接:click here 题意:输出第N个能被3或者5整除的数,注意是||而不是&&. 代码: <pre name="code" class="cpp">//zoj 2829 #include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #include <math.h> using

ZOJ 2319 Beatuiful People(单调上升子序列变形)

Beautiful People Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge 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 b

ASC #1

开始套题训练,第一套ASC题目,记住不放过每一题,多独立思考. Problem A ZOJ 2313 Chinese Girls' Amusement 循环节 题意:给定n,为圆环长度,求k <= n/2,从1出发,每次顺时针方向走k步,即1->k+1->2*k+1,直到遇到一个已经走过的点结束,要求最终把所有点访问一遍,最后回到1,使得k尽量大. 代码: Problem B ZOJ 2314 Reactor Cooling 无源汇上下界网络流 题意:经典题,有上下界无源无汇的可行流,对

插头与轮廓线与基于连通性状态压缩的动态规划

问题定义 什么是插头DP 在一个n*m的棋盘上(n与m很小),求: 有多少种不同的回路数 用1条回路经过所有点的方案数 用1条回路经过部分点的方案数 1条路径上的权值和最大 的这一类问题,通常可以用插头DP来解决. 这类问题通常很明显,但代码量大又容易出错,有时TLE有时MLE. 什么是基于状态压缩的动态规划 基于状态压缩的动态规划问题是一类以集合信息为状态且状态总数为指数级的特殊的动态规划问题. 在状态压缩的基础上,有一类问题的状态中必须要记录若干个元素的连通情况,我们称这样的问题为基于连通性

插头dp的几个模板

/* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring> #include<string> #include<iostream> #include<algorithm> #include<cmath> #include<map> #include<queue> #define LL lon

插头DP专题

建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议先理解“插头”的概念.然后会HASH表(这个其实是很基础的东西,应该都会的).然后就是DP. 以及特殊题目的特殊处理. 好像一般是求N,M<=12的网格图的某种回路数或某种通路数的方案数. 大体上每个题说几句特殊处理,有问题请纠正....题目的顺序基本上难度递增 另外代码我都是用括号匹配的.因为感觉连通

ZOJ 2833-Friendship(并查集+优化)

Friendship Time Limit: 3 Seconds      Memory Limit: 32768 KB A friend is like a flower, a rose to be exact, Or maybe like a brand new gate that never comes unlatched. A friend is like an owl, both beautiful and wise. Or perhaps a friend is like a gho

HDU 4430 &amp; ZOJ 3665 Yukari&#39;s Birthday(二分+枚举)

题目链接: HDU:http://acm.hdu.edu.cn/showproblem.php?pid=4430 ZJU:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4888 Problem Description Today is Yukari's n-th birthday. Ran and Chen hold a celebration party for her. Now comes the most import