神仙题啊,感觉这道题比platinum可做一些
一开始xjb手玩玩得整个人都不好了 甚至不加分析乱写 只能过样例的那种
根据题意,其实它还是个冒泡排序,考虑每次交换
每次向后冒泡跨过的位置的下标一定是小于排序后这个数字对应的位置下标的
这时考虑离散化,不过并不能用那种 sort + unique + lower_bound 那种
这是因为此题中要的操作是排序,数字大小和其下标都会有影响,
所以要换一种离散化的方式
for(int i = 1; i <= n; ++i) { scanf("%d", &a[i].num); a[i].id = i; } sort(a + 1, a + n + 1, cmp1); for(int i = 1; i <= n; ++i) a[i].num = i; sort(a + 1, a + n + 1, retn);
第一次 sort 先按大小 再按下标排序
这样按顺序给每个数字更新对应的值,相当于是考虑了位置和数值大小的影响的
第二次 sort 按初始下标排序,就是恢复原序列
然后权值线段树或树状数组查询前 i 个数中大于 i 的数的个数
注意如果原序列不需要排序的话还是要扫描一遍的,所以 ans 初值为 1
感觉这题离散化不太好写= =
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cctype> #include<cstdio> using namespace std; const int MAXN = 100005; struct Node{ int num, id; }a[MAXN]; int n, ans = 1; int t[MAXN]; inline int lowbit(int x) { return (x & (-x)); } inline void add(int x, int val) { for( ; x <= n; x += lowbit(x)) t[x] += val; return; } inline int query(int x) { register int sum = 0; for( ; x; x -= lowbit(x)) sum += t[x]; return sum; } inline bool cmp1(Node a, Node b) { return (a.num == b.num ? (a.id < b.id) : (a.num < b.num)); } inline bool retn(Node a, Node b) { return a.id < b.id; } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d", &a[i].num); a[i].id = i; } sort(a + 1, a + n + 1, cmp1); for(int i = 1; i <= n; ++i) a[i].num = i; sort(a + 1, a + n + 1, retn); for(int i = 1; i <= n; ++i) { add(a[i].num, 1); ans = max(ans, query(n) - query(i)); } printf("%d ", ans); return 0; }