洛谷 P4378 [USACO18OPEN]Out of Sorts S(树状数组求冒泡排序循环次数)
https://www.cnblogs.com/violet-acmer/p/9833502.html
要回宿舍休息了,题解明天再补吧。
题解:
定义一数组 a[maxn]
考察冒泡排序的本质。
冒泡排序,每次会把最大的数直接沉底,但是比较小的数,会往前面缓慢冒泡。
具体来说,如果一个数 val 在数组有序后的排名是 i ,但是目前位置在 i 之后,那么,每次循环,val 必然会往前面移动一位。
因为前面必然会有一个比 val 大的数往后沉。
swap的次数,就是逆序对数
循环的次数,就是max( i 前比a[i]大的数的个数)(i=1,2,3,......,n)
注意事项:
(1):首先需要做的是离散化原数组,因为 a[i] 的值最大可达 1e9,但 n 最大才 1e5,注意在排序的时候,对于值相同的两个数,初始编号小的在前。
(2):最终结果要额外 +1
AC代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 using namespace std; 5 #define lowbit(x) (x&(-x)) 6 const int maxn=1e5+50; 7 8 int N; 9 struct Node 10 { 11 int val; 12 int id;//存储初始编号 13 int newVal;//存储离散化后 val 对应的新值 14 }a[maxn]; 15 //==============BIT=================== 16 int bit[maxn]; 17 void Add(int x) 18 { 19 while(x <= N) 20 { 21 bit[x]++; 22 x += lowbit(x); 23 } 24 } 25 int Sum(int x) 26 { 27 int sum=0; 28 while(x > 0) 29 { 30 sum += bit[x]; 31 x -= lowbit(x); 32 } 33 return sum; 34 } 35 //===================================== 36 bool cmp(Node _a,Node _b){ 37 //值不同,值小的在前;值相同,初始编号小的在前,保证排序的稳定性 38 return _a.val < _b.val || (_a.val == _b.val && _a.id < _b.id); 39 } 40 bool cmp1(Node _a,Node _b){ 41 return _a.id < _b.id; 42 } 43 void Solve() 44 { 45 sort(a+1,a+N+1,cmp); 46 for(int i=1;i <= N;++i) 47 a[i].newVal=i;//离散化后的对应的值,虽然可能大小变了,但其对应的相对次序是不变的 48 sort(a+1,a+N+1,cmp1);//恢复原数组对应的顺序 49 int res=0; 50 for(int i=1;i <= N;++i) 51 { 52 //Sum(a[i].newVal) : i 之前,数值不大于a[i].newVal 的个数 53 //i-1-Sum(a[i].newVal) : i 之前,数值大于a[i].newVal的个数 54 //而答案就是 max(i-1-Sum(a[i].newVal) 55 res=max(res,i-1-Sum(a[i].newVal)); 56 Add(a[i].newVal); 57 } 58 printf("%d\n",res+1);//最终结果要加1,因为不管当前交换完后是否有序,都需要额外输出一个 moo 来判断是否有序 59 } 60 int main() 61 { 62 scanf("%d",&N); 63 for(int i=1;i <= N;++i) 64 { 65 scanf("%d",&a[i].val); 66 a[i].id=i; 67 } 68 Solve(); 69 }