• hdu 5792 World is Exploding 树状数组+离散化+容斥


    World is Exploding

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 727    Accepted Submission(s): 348


    Problem Description
    Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: abcd,1a<bn,1c<dn,Aa<Ab,Ac>Ad.
     
    Input
    The input consists of multiple test cases. 
    Each test case begin with an integer n in a single line.

    The next line contains n integers A1,A2An.
    1n50000
    0Ai1e9
     
    Output
    For each test case,output a line contains an integer.
     
    Sample Input
    4 2 4 1 3 4 1 2 3 4
     
    Sample Output
    1 0
     
    Author
    ZSTU
     
    Source
     题意:给你n个数字,要求从中找到下标i<j,a[i]<a[j];p<q,a[p]>a[q]且i,j,p,q互不相等的组数;
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <algorithm>
    using namespace std;
    typedef  long long  ll;
    typedef unsigned long long ull;
    #define MM(a,b) memset(a,b,sizeof(a));
    #define inf 0x7f7f7f7f
    #define FOR(i,n) for(int i=1;i<=n;i++)
    #define CT continue;
    #define PF printf
    #define SC scanf
    const int mod=1000000007;
    const int N=1e6+10;
    int tmp[N],a[N],n,m,c[N],pos[N];
    ll lmin[N],rmin[N],lmax[N],rmax[N];
    
    int lowbit(int i)
    {
        return i&(-i);
    }
    
    void add(int x)
    {
        while(x<=m)
        {
          c[x]+=1;
          x+=lowbit(x);
        }
    }
    
    int query(int x)
    {
        int res=0;
        while(x>0)
        {
            res+=c[x];
            x-=lowbit(x);
        }
        return res;
    }
    
    int main()
    {
        while(~scanf("%d",&n))
        {
             for(int i=1;i<=n;i++)
              {
                  scanf("%d",&tmp[i]);
                  a[i]=tmp[i];
              }
    
             sort(tmp+1,tmp+n+1);
             m=unique(tmp+1,tmp+n+1)-tmp-1;
    
             for(int i=1;i<=n;i++)
                 pos[i]=lower_bound(tmp+1,tmp+m+1,a[i])-tmp;
    
             MM(c,0);
             for(int i=1;i<=n;i++)
             {
                 lmin[i]=query(pos[i]-1);
                 lmax[i]=query(m)-query(pos[i]);
                 add(pos[i]);
             }
    
    
             MM(c,0);
             for(int i=n;i>=1;i--)
             {
                 rmin[i]=query(pos[i]-1);
                 rmax[i]=query(m)-query(pos[i]);
                 add(pos[i]);
             }
    
             ll ans=0,l=0,r=0;
             for(int i=1;i<=n;i++)  {r+=rmax[i],l+=lmax[i];};
             ans=l*r;
             for(int i=1;i<=n;i++)
             {
                 ans-=lmin[i]*rmin[i];
                 ans-=lmax[i]*rmax[i];
                 ans-=lmax[i]*lmin[i];
                 ans-=rmax[i]*rmin[i];
             }
             printf("%lld
    ",ans);
        }
        return 0;
    }
    

      分析:比赛的时候又是只想到暴力枚举,结果发现肯定超时,复杂度又不会降下来,就跪了。。。

    后来看了下题解,结果发现跟以前做的一道题很像。是以前做过的题的综合。

    解决:既然超时了的话,就想想通过什么办法把复杂度降下来,,于是BIT,BIT可以在logn的时间内

    求出每个点两侧>或<的数的个数;

    BIT:因为只关心数据的相对大小,数据范围又很大,所以需要离散化

    离散化:sort排好序后,用unique去重,然后对于原数组的每个数,利用lower_bound();找到其在去重

    之后数组中的位置,记录下来,作为在BIT中的位置。

    按原来的顺序枚举每个数,对于query(pos[i]-1)为查找在1-i中小于其的数的个数。query(m)-query(pos[i])为在1-i中>其的个数,因为是从小到大枚举所以都是l;然后将其在BIT中的对应位置的值+1,

    然后从大到小枚举一下

     

  • 相关阅读:
    面试求职:数据库常见面试题(数据库优化思路)
    数据库优化面试内容
    nginx笔记-3
    webpack-问题记录
    [Tips] Linux查看系统环境变量
    解决input框中加入disabled="disabled"之后,改变字体的颜色(默认的是灰色)
    js 中日期转换成时间戳
    Day09_课程预览 Eureka Feign
    Day08_课程图片管理与分布式文件系统
    Day08_分布式文件系统FastDFS研究
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5735881.html
Copyright © 2020-2023  润新知