时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个1-N的排列A1, A2, ... AN,如果Ai和Aj满足i < j且Ai > Aj,我们就称(Ai, Aj)是一个逆序对。
求A1, A2 ... AN中所有逆序对的数目。
输入
第一行包含一个整数N。
第二行包含N个两两不同整数A1, A2, ... AN。(1 <= Ai <= N)
对于60%的数据 1 <= N <= 1000
对于100%的数据 1 <= N <= 100000
输出
一个整数代表答案
- 样例输入
-
5 3 2 4 5 1
- 样例输出
-
5
求逆序对,两种方法,一个是用树形数组做,一个是用归并排序做。两种都试了一遍,有一个地方比较坑就是数组类型必须是long long。不然会WA,题目却没有明显信息说要long long。。这个地方可以说是很坏坏了。
树形数组ac代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<vector> 6 #include<iomanip> 7 using namespace std; 8 9 10 //1524 : 逆序对 11 const int maxn = 1e5 + 5; 12 int n; 13 long long a[maxn], b[maxn]; 14 int lowbit(int i) 15 { 16 return i&-i; 17 } 18 void update(int i) 19 { 20 while (i <= n) 21 { 22 b[i]++; 23 i += lowbit(i); 24 } 25 } 26 long long sum(int i) 27 { 28 long long cnt = 0; 29 while (i) 30 { 31 cnt += b[i]; 32 i -= lowbit(i); 33 } 34 return cnt; 35 } 36 int main() 37 { 38 cin >> n; 39 for (int i = 1;i <= n;i++) 40 { 41 cin >> a[i]; 42 } 43 memset(b, 0, sizeof(b)); 44 long long res = 0; 45 for (int i = n;i >= 1;i--) 46 { 47 update(a[i]); 48 res += sum(a[i] - 1); 49 } 50 cout << res << endl; 51 return 0; 52 }
树形数组这个东西还是比较有趣的。这个算法可以说是比较天才了。
具体的树形数组详解可以看这个博主的http://blog.csdn.net/ljd4305/article/details/10101535
归并排序的ac代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<vector> 6 #include<iomanip> 7 using namespace std; 8 9 10 //1524 : 逆序对 11 const int maxn = 1e5 + 5; 12 int n; 13 long long a[maxn],b[maxn]; 14 long long cnt; 15 16 void merge_sort(long long * a, int l, int r) 17 { 18 int mid = (l + r) >> 1; 19 int m = l, n = mid + 1; 20 int pos = l; 21 while (m<=mid&&n<=r) 22 { 23 if (a[m] < a[n]) 24 { 25 b[pos++] = a[m++]; 26 } 27 else 28 { 29 b[pos++] = a[n++]; 30 cnt+=mid-m+1; 31 } 32 } 33 34 while (m <= mid) b[pos++] = a[m++]; 35 while (n <= r) b[pos++] = a[n++]; 36 for (int i = l;i <= r;i++) 37 a[i] = b[i]; 38 } 39 void merge(long long * a, int l, int r) 40 { 41 if (l >= r) return; 42 int mid = (l + r) >>1; 43 merge(a, l, mid); 44 merge(a, mid+1, r); 45 merge_sort(a, l, r); 46 } 47 48 int main() 49 { 50 cnt = 0; 51 cin >> n; 52 for (int i = 1;i <= n;i++) 53 { 54 cin >> a[i]; 55 } 56 merge(a, 1, n); 57 cout << cnt << endl; 58 return 0; 59 }
归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并排序中的合并过程中计算逆序数。
可以参考http://blog.csdn.net/acdreamers/article/details/16849761
时间: 2024-12-06 23:50:25