noip模拟赛 序

【问题背景】
zhx 给他的妹子们排序。
【问题描述】
zhx N 个妹子, 他对第 i 个妹子的好感度为 ai,且所有 ai两两不相等。 现
N 个妹子随意站成一排, 他要将她们根据好感度从小到大排序。 他使用的是
冒泡排序算法(详见下)。如果排序过程中好感度为 ai的妹子和aj的妹子发生了交换, 那么她们之间会发生一场口角。
现在 zhx 想知道, 给定妹子的初始排列, 在排序完成后, 最多存在多少个妹
子, 她们任意两人之间没发生过口角。

【输入格式】 

第一行两个整数 N, 表示妹子数量。
接下来一行 N 个整数 ai,表示初始第i个妹子的好感度.
【输出格式】
一行一个整数, 表示最多满足要求的妹子的个数。
【样例输入】
3
3 1 2
【样例输出】
2
【样例解释】
{1, 2}
对于100%的数据, 1 ≤   N ≤ 100000,0≤ai<N.
分析:要找到这个集合,首先要搞清楚这个集合中的元素满足什么性质.冒泡排序和逆序对是相关的,每一对逆序对的两个数都会被交换一次.那么最后的集合中两两肯定都是顺序对,即i<j,a[i]<a[j],现在要求最大的集合,这就是LIS.数据比较大,要用O(NlogN)的解法.

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n, a[100010], s[100010], cur;

int erfen(int x)
{
    int l = 1, r = cur, ans = 1;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (s[mid] > x)
        {
            r = mid - 1;
            ans = mid;
        }
        else
            l = mid + 1;
    }
    return ans;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    s[0] = -1;
    for (int i = 1; i <= n; i++)
    {
        if (a[i] > s[cur])
            s[++cur] = a[i];
        else
        {
            int p = erfen(a[i]);
            s[p] = a[i];
        }
    }
    printf("%d
", cur);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7736758.html