本题就是求逆序数,在一个排列中,如果一对数的前后位置与大小
顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
令t[i]表示逆序对(a[j],i)的个数,即排在i的左边且比i大的数的个数,则逆序数为t[1]+t[2]+···t[n]
例l设n=8,a={3,2,l,5,8,4,6,7},t[1] = 2 ,t[2] = 1,t[3] = 0,t[4] = 1,t[5] = 0,t[6] = t[7] = 1,t[8] = 0;
数状数组计算逆序数:计算a[1]+a[2]+a[3]····+a[n]的逆序数,num = t[1]+t[2]+·····+t[n];
算法:
sum = 0;
for(i = l; i <= n; ++i)
b[a[i]] = i;
for(i = 1; i <= n; ++i)
c[i] = 0;
for(x = n; x>=l; --x)
{
p=b[x];
sum += Querry(p);
UFset(p, 1);
}//本题代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 500010; int c[MAXN]; struct Node { int seq, val; }s[MAXN]; int lowbit(int x) { return x & (-x); } void UFset(int pos, int data) { while(pos < MAXN) { c[pos] += data; pos += lowbit( pos ); } } __int64 Querry(int pos) { __int64 sum = 0; while(pos > 0) { sum += c[pos]; pos -= lowbit( pos ); } return sum; } bool cmp(Node a, Node b) { return a.val < b.val; } int main() { int n; int b[MAXN]; while(scanf("%d", &n) != EOF && n) { for(int i = 1;i <= n; ++i) { scanf("%d",&s[i].val); s[i].seq = i; } memset(c, 0, sizeof(c)); memset(b, 0, sizeof(b)); sort(s+1, s+1+n, cmp); for(int i = 1; i <= n; ++i) b[ s[i].seq ] = i; __int64 sum = 0; for(int i = n; i >= 1; --i) { sum += Querry( b[i] ); UFset(b[i], 1); } printf("%I64d\n", sum); } return 0; }