题目地址:http://codeforces.com/contest/459/problem/D
这个题攒了好长时间了,一直也没看。。今天看了下,也不难。当时做的时候明明还有半个多小时可以看这题的,但是。。由于某些人的打扰。。我一直在应付着拒绝。。所以这题当时连看都没来得及看。。以后做CF果断不上QQ了。。。
这题就是求逆序数。需要先预处理每个点的左边与右边与之相同的数的个数。然后用线段树去求逆序数就可以了。因为数的范围是10^9,而数据范围只有10^6,所以要先对其离散化。
代码如下:
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include <set> #include <algorithm> using namespace std; #define lson l, mid, rt<<1 #define rson mid+1, r, rt<<1|1 #define LL __int64 int dp1[1100000], dp2[1100000], a[1100000], b[1100000], c[1100000], _hash[1100000]; LL sum[5100000]; void PushUp(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void update(int p, int l, int r, int rt) { if(l==r) { sum[rt]++; return ; } int mid=l+r>>1; if(p<=mid) update(p,lson); else update(p,rson); PushUp(rt); } LL query(int ll, int rr, int l, int r, int rt) { if(ll<=l&&rr>=r) return sum[rt]; int mid=l+r>>1; LL ans=0; if(ll<=mid) ans+=query(ll,rr,lson); if(rr>mid) ans+=query(ll,rr,rson); return ans; } int erfen(int x, int high) { int low=0, mid; while(low<=high) { mid=low+high>>1; if(c[mid]>x) high=mid-1; else if(c[mid]<x) low=mid+1; else return mid; } } int main() { int n, i, cnt=1, max1=-1; scanf("%d",&n); LL ans=0; for(i=1;i<=n;i++) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); c[0]=b[1]; for(i=2;i<=n;i++) { if(b[i]!=b[i-1]) { c[cnt++]=b[i]; } } for(i=1;i<=n;i++) { a[i]=erfen(a[i],cnt-1); } memset(_hash,0,sizeof(_hash)); for(i=1;i<=n;i++) { dp1[i]=++_hash[a[i]]; max1=max(max1,dp1[i]); } memset(_hash,0,sizeof(_hash)); for(i=n;i>=1;i--) { dp2[i]=++_hash[a[i]]; } memset(sum,0,sizeof(sum)); /*for(i=n;i>=1;i--) { printf("%d ",dp1[i]); } printf("\n"); for(i=n;i>=1;i--) { printf("%d ",dp2[i]); } printf("\n");*/ for(i=n;i>=1;i--) { ans+=query(0,dp1[i]-1,0,max1,1); update(dp2[i],0,max1,1); //printf("%I64d\n",ans); } printf("%I64d\n",ans); return 0; }