题目地址: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;
}