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\n", cur); return 0; }