感觉自己的做法比较奇葩。
真没想到这个奇葩做法快到358ms;
看到别人的代码耗时都是1000ms+,有点小激动咯;
因为数比较大,所以先离散化一下,把离散化后的数存在数组li [1000005 ]里,然后用cnt2数组记录 F( j , n , a[j] );
然后得到F( 1 , i , a[i] ),存在数组cnt1里。这个时候的问题要想满足F( 1 , i , a[i] ) >F( j , n , a[j] ); 就是看对区间 [ 1 , i ]内有多少的数比cnt2 [ i+1 ]大 ,所以就用了速度较快的树状数组来查询,最后每次查询的结果相加就是答案了;
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
int _max,li[1000005],tree[1000005];
int vis[1000005],cnt1[1000005],cnt2[1000005];
struct node{
int v,id;
}a[1000005];
bool cmp(struct node a,struct node b)
{
return a.v<b.v;
}
void update(int pos,int val)
{
while(pos<=_max+1)
{
tree[pos]+=val;
pos+=pos&(-pos);
}
}
int read(int pos)
{
int ans=0;
while(pos>0)
{
ans+=tree[pos];
pos-=pos&(-pos);
}
return ans;
}
int main()
{
int n;
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=1;i<=n;i++) {scanf("%d",&a[i].v);a[i].id=i;}
sort(a+1,a+1+n,cmp);
int vv=a[1].v,tt=0;
//离散化数据
for(int i=1;i<=n;i++)
{
if(vv!=a[i].v) tt++,vv=a[i].v;
li[a[i].id]=tt;
}
// for(int i=1;i<=n;i++) printf("%d ",li[i]);
_max=-1;
//得到<span style="font-size:18px;">F( j , n , a[j] );</span>
for(int i=n;i>=1;i--)
{
vis[li[i]]++;
cnt2[i]=vis[li[i]];
_max=max(_max,cnt2[i]);
}
// for(int i=1;i<=n;i++) printf("%d ",cnt2[i]);
memset(vis,0,sizeof(vis));
memset(tree,0,sizeof(vis));
long long ans=0;
for(int i=1;i<n;i++)
{
vis[li[i]]++;
cnt1[i]=vis[li[i]];
update(cnt1[i],1);
//printf("%d %d\n",read(_max+1),read(cnt2[i+1]));
ans+=i-read(cnt2[i+1]);
}
printf("%I64d\n",ans);
return 0;
}