这道题我是按照mergecnt做的,即原题等同于求数组中的inversion count(前面的数比后面的数大的pair的个数)。然后在merge sort中统计一下这样的对有多少个就可以。时间复杂度和merge sort一样,都是O(nlogn)。
geeksforgeeks上面有很好的解释和实现:http://www.geeksforgeeks.org/counting-inversions/
最终结果要用long long表示,因为逆对数的范围是n^2,即50w * 50w = 2.5 * 10^9,没有意识到这一点贡献了一次WA。
discuss和网上都有用线段树求逆对数的,方法很巧妙,需要首先离散化:http://www.cnblogs.com/frog112111/p/3268632.html
2299 | Accepted | 3744K | 1282MS | C++ | 1350B |
/*
ID: thestor1
LANG: C++
TASK: poj2299
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
const int MAXN = 500000;
// const int MAXN = 10;
int nums[MAXN];
int tmp[MAXN];
void mergecnt(int left, int right, long long &cnt)
{
if (left >= right)
{
return;
}
int mid = left + (right - left) / 2;
mergecnt(left, mid, cnt);
mergecnt(mid + 1, right, cnt);
int i, j, k = left;
for (i = left, j = mid + 1; i <= mid && j <= right;)
{
if (nums[i] <= nums[j])
{
tmp[k] = nums[i];
i++;
k++;
}
else
{
// nums[i] > nums[j]
cnt += mid - i + 1;
tmp[k] = nums[j];
j++;
k++;
}
}
while (i <= mid)
{
// cnt += mid - i + 1;
tmp[k] = nums[i];
i++;
k++;
}
while (j <= right)
{
tmp[k] = nums[j];
j++;
k++;
}
for (i = left; i <= right; ++i)
{
nums[i] = tmp[i];
}
}
int main()
{
int N;
while (cin >> N && N)
{
for (int i = 0; i < N; ++i)
{
cin >> nums[i];
}
long long cnt = 0;
mergecnt(0, N - 1, cnt);
cout << cnt << endl;
}
return 0;
}