逆序数 POJ 2299 Ultra-QuickSort

题目传送门

  1 /*
  2     暴力 超时
  3 */
  4 #include <stdio.h>
  5
  6 const int MAX_N = 500000;
  7 int a[MAX_N+10];
  8 long long cnt = 0;
  9
 10 int main(void)
 11 {
 12     //freopen ("inD.txt", "r", stdin);
 13     int n;
 14
 15     while (scanf ("%d", &n) != EOF && n)
 16     {
 17         for (int i=1; i<=n; ++i)
 18         {
 19             scanf ("%d", &a[i]);
 20         }
 21
 22         for (int i=1; i<=n; ++i)
 23         {
 24             for (int j=i+1; j<=n; ++j)
 25             {
 26                 if (a[i] > a[j])
 27                     cnt++;
 28             }
 29         }
 30         printf ("%lld\n", cnt);
 31         cnt = 0;
 32     }
 33
 34     return 0;
 35 }
 36
 37 /*
 38     题目的意思就是要求冒泡排序的交换次数。
 39     所用的算法:用归并排序,求逆序数的个数。
 40
 41     归并排序是将数列a[p, r]分成两半a[p, q]和a[q+1,r]分别进行归并排序,
 42     然后再将这两半合并起来。在合并的过程中(设p<=i<=q,q+1<=j<=r),
 43     当L[i]<=R[j]时,并不产生逆序数;
 44     当L[i]>R[j]时,在前半部分中比L[i]大的数都比R[j]大,
 45     将R[j]放在L[i]前面的话,逆序数要加上q+1-i。
 46     因此,可以在归并排序中的合并过程中计算逆序数。
 47
 48     这道题充分印证了,即使merge本身可能用的不多,但分冶的思想却是无所不在
 49
 50 */
 51 #include <stdio.h>
 52
 53 const int MAX_N = 500000;
 54 int a[MAX_N+10];
 55 long long cnt = 0;
 56
 57 const int INF = 0xffffff;
 58
 59 void Merge(int *a, int p, int q, int r)
 60 {
 61     int n1 = q - p + 1;
 62     int n2 = r - q;
 63     int L[MAX_N/2+1], R[MAX_N/2+1];
 64     int i, j;
 65     for (i=1; i<=n1; ++i)
 66     {
 67         L[i] = a[p+i-1];
 68     }
 69     for (j=1; j<=n2; ++j)
 70     {
 71         R[j] = a[q+j];
 72     }
 73     L[n1+1] = INF;    R[n2+1] = INF;
 74     i = 1;    j = 1;
 75     for (int k=p; k<=r; ++k)
 76     {
 77         if (L[i] <= R[j])
 78         {
 79             a[k] = L[i];
 80             i++;
 81         }
 82         else
 83         {
 84             a[k] = R[j];
 85             ++j;
 86             cnt += n1 - i + 1;         //此步骤是在归并排序法中加的一句,用来计数求逆序数的数目
 87
 88         }
 89     }
 90 }
 91
 92 void MergeSort(int *a, int p, int r)
 93 {
 94     int q;
 95
 96     if (p < r)
 97     {
 98         q = (p + r) / 2;
 99         MergeSort (a, p, q);
100         MergeSort (a, q+1, r);
101         Merge (a, p, q, r);
102     }
103 }
104
105 int main(void)        //POJ 2299 Ultra-QuickSort
106 {
107     //freopen ("inD.txt", "r", stdin);
108     int n;
109
110     while (scanf ("%d", &n) != EOF && n)
111     {
112         for (int i=1; i<=n; ++i)
113         {
114             scanf ("%d", &a[i]);
115         }
116         MergeSort (a, 1, n);
117         printf ("%lld\n", cnt);
118         cnt = 0;
119     }
120
121     return 0;
122 }
123
124 /*
125     线段树-单点更新
126 */
127 #include <cstdio>
128 #include <algorithm>
129 #define lson l, m, rt << 1
130 #define rson m+1, r, rt << 1 | 1
131 using namespace std;
132
133 const int MAX_N = 500000;
134 const int INF = 0x3f3f3f3f;
135 int a[MAX_N];
136 int b[MAX_N];
137 int sum[MAX_N << 2];
138
139 void pushup(int rt)
140 {
141     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
142 }
143
144 void build(int l, int r, int rt)
145 {
146     sum[rt] = 0;
147     if (l == r) return ;
148     int m = (l + r) >> 1;
149     build (lson);
150     build (rson);
151
152     pushup (rt);
153 }
154
155 void update(int p, int l, int r, int rt)
156 {
157     if (l == r)
158     {
159         sum[rt]++;      //记录次数
160         return ;
161     }
162     int m = (l + r) >> 1;
163     if (p <= m)
164     {
165         update (p, lson);
166     }
167     else
168         update(p, rson);
169     pushup (rt);
170 }
171
172 int query(int ql, int qr, int l, int r, int rt)
173 {
174     if (ql <= l && r <= qr)
175     {
176         return sum[rt];
177     }
178     int m = (l + r) >> 1;
179     int ans = 0;
180     if (ql <= m)    ans += query (ql, qr, lson);
181     if (qr > m)     ans += query (ql, qr, rson);
182
183     return ans;
184 }
185
186 int BinarySearch(int key, int l, int r)
187 {
188     while (r >= l)
189     {
190         int mid = (l + r) >> 1;
191         if (key == b[mid])    return mid;
192         if (key < b[mid])    r = mid - 1;
193         else    l = mid + 1;
194     }
195 }
196
197 int main(void)
198 {
199     //freopen ("inD.txt", "r", stdin);
200     int n;
201     while (~scanf ("%d", &n) && n)
202     {
203         build (0, n-1, 1);
204
205         for (int i=1; i<=n; ++i)
206         {
207             scanf ("%d", &a[i]);
208             b[i] = a[i];
209         }
210         sort (b+1, b+n+1);
211         long long ans = 0;
212         for (int i=1; i<=n; ++i)
213         {
214             int x = BinarySearch (a[i], 1, n);
215             ans += query (x, n, 1, n, 1);
216             update (x, 1, n, 1);
217         }
218         printf ("%lld\n", ans);
219     }
220
221     return 0;
222 }
223
224 /*
225     树状数组
226 */
时间: 2024-11-05 11:24:45

逆序数 POJ 2299 Ultra-QuickSort的相关文章

(离散化+树状数组求逆序数) poj 2299

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 44390   Accepted: 16149 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

poj 2299 Ultra-QuickSort 归并排序求逆序数对

题目链接: http://poj.org/problem?id=2299 题目描述: 给一个有n(n<=500000)个数的杂乱序列,问:如果用冒泡排序,把这n个数排成升序,需要交换几次? 解题思路: 根据冒泡排序的特点,我们可知,本题只需要统计每一个数的逆序数(如果有i<j,存在a[i] > a[j],则称a[i]与 a[j]为逆序数对),输出所有的数的逆序数的和用普通排序一定会超时,但是比较快的排序,像快排又无法统计 交换次数,这里就很好地体现了归并排序的优点.典型的利用归并排序求逆

poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)

题目链接:http://poj.org/problem?id=2299 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in

poj 2299 Ultra-QuickSort (归并排序,逆序数)

链接:poj 2299 题意:给出长度为n的序列,每次只能交换相邻的两个元素, 问至少要交换几次才使得该序列为递增序列 分析:冒泡排序每次只能交换相邻两个元素,也就是求 用冒泡排序使其为递增序列的交换次数,每交换一次记录一次就好 但是这题数据较大,冒泡排序效率比较低,会超时的 这里就可以利用归并排序了,用归并排序可以求序列的逆序数, 而一个序列的 逆序数 = 只允许相邻两个元素交换时,得到有序序列的交换次数 #include<stdio.h> #include<stdlib.h>

poj 2299 树状数组求逆序数+离散化

http://poj.org/problem?id=2299 最初做离散化的时候没太确定但是写完发现对的---因为后缀数组学的时候,,这种思维习惯了吧 1.初始化as[i]=i:对as数组按照num[]的大小间接排序 2.bs[as[i]]=i:现在bs数组就是num[]数组的离散化后的结果 3.注意,树状数组中lowbit(i)  i是不可以为0的,0&(-0)=0,死循环... #include <cstdio> #include <cstring> #include

poj 2299 逆序数

http://poj.org/problem?id=2299 坑:答案是long long 输出……!!!!! 题意是:求一个数组进行冒泡排序交换的次数 题解:求逆序数 题解Ⅰ: 归并排序求逆序数 归并排序求逆序数之前写过 1.归并排序是把两个有序的数组合并成为一个有序的数组,利用分治的思想就可以进行排序 逆序数可以利用这个思想求 求出第一个数组的逆序数,和第二个数组的逆序数,再将两个数组整体的逆序数求出来 f(x,y) = f(x,mid) + f(mid,y) + 之后数组的逆序数 #inc

POJ 2299 Ultra-QuickSort (归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 47235   Accepted: 17258 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

归并排序求逆序数(POJ 1804,POJ 2299,HDU 4911)

首先,明确两个概念: 逆序对:数列a[1],a[2],a[3]-中的任意两个数a[i],a[j] (i<j),如果a[i]>a[j],那么我们就说这两个数构成了一个逆序对. 逆序数:一个数列中逆序对的总数. 例题一:POJ 1804.   点击打开链接 解题思路:每次交换只能减少一个逆序,而且必定能减少一个逆序,从而问题就转换为求逆序个数了.这题数据规模很小,暴力可过. 我这里提供了用Merge_sort的方法求解逆序数,时间复杂度为O(nlogn). 关于归并排序:归并排序是将数列a[l,h

poj-2299 Ultra—QuickSort(归并排序求逆序数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 38688   Accepted: 13950 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin