Codeforces Round #261 (Div. 2) D题

    感觉自己的做法比较奇葩。

    真没想到这个奇葩做法快到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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值