Codeforces Beta Round #57 (Div. 2) E. Enemy is weak

来源:互联网 发布:软件外包服务商排名 编辑:程序博客网 时间:2024/05/22 02:10

题目:http://codeforces.com/problemset/problem/61/E

题意:若一个组数下标 i<j<k以及ai>aj>ak 则为一个弱点,计算一组数据中有几个弱点。

思路:1)使用树状数组,从左到右扫描所有的数,令数组a 表示目前为止 已经考虑过的所有的数num,是否存在一个,存在则a[j]=1,不存在则a[j]=0。在计算一个数前面比它的大   数和后面比它小的数可以计算前缀和和后缀和。

            2)  先从前往后搜索数组,使用数组a1记录每一个数前面比它大的的数的个数,使用数组a2记录每一个数后面比它小的数的个数。当以数n1为中间数是有a1*a2个弱点。

            3)由于数的大小为1 ≤ ai ≤ 109,无法开这么大的数组来记录数是否存在。使用数的离散化,将数列排序,使用数组的下标代表代表数的相对大小。使用二分查找lower_bound来查找原数组n1在已排序数组num在的下标。

*注意:树状数组不能从0开始存!所以可以将所有的数组的开头下标设为1。

CODE;

#include <iostream>#include <stdio.h>#include <algorithm>const int N=1000005;using namespace std;int n1[N],num[N],a[N],c[N];int T;int lowbit(int xx){    return xx&-xx; //树状数组不能从0开始存}void add(int x,int d){    while(x<=T)    {        c[x]+=d;        x+=lowbit(x);    }}int sum(int x){    int ret=0;    while(x>0)    {        ret+=c[x];        x-=lowbit(x);    }    return ret;}bool cmp(int a,int b){    return a<b;}long long a1[N],a2[N];int main(){    //freopen("in.in","r",stdin);    while(~scanf("%d",&T))    {        fill(a,a+T+1,0);        fill(c,c+T+1,0);        for(int i=1;i<=T;i++)        {            scanf("%d",&n1[i]);            num[i]=n1[i];        }        sort(num+1,num+T+1,cmp);        long long ans=0;        for(int i=1;i<=T;i++)        {            int k=lower_bound(num,num+T+1,n1[i])-num;            a[k]=1;            add(k,1);            a1[i]=sum(T)-sum(k);        }        fill(a,a+T+1,0);        fill(c,c+T+1,0);        for(int i=T;i>=1;i--)        {            int k=lower_bound(num,num+T+1,n1[i])-num;            a[k]=1;            add(k,1);            a2[i]=sum(k-1);        }        for(int i=1;i<=T;i++)            ans+=a1[i]*a2[i];        printf("%I64d\n",ans);    }    return 0;}


0 0