HDU 5792 World is Exploding

题意:

给出n代表序列的长度,接下来给出序列A。找出abcd满足abcd互不相等1<=a<b<c<d<=n的同时A[a]<A[b],A[c]>A[d],问这样的abcd有几个.

思路:先忽略四个数两两不相等的条件,那就是(,逆序对个数)乘上(顺序对个数)。例如{2,4,1,3},逆序对就是{(2,1),(4,1),(4,3)} ,顺序对就是{(2,4),(2,3),(1,3)},这样3*3=9,一共九个符合a<b && c>d的四元组。但其中有很多不合法的,对于t这个数,不合法情况的个数就是 (关于t的逆序对个数×关于t的顺序对个数),一一减去就是结果了。(不合法的规律多写几组便能找到)

输入:

4

2 4 1 3

4

1 2 3 4

输出:

1
0

代码:

#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);//将tmp按从小到大排序,用于树状数组查找顺/逆序对

         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;//找到原来的第i个数在排序后应在的位置

 

         MM(c,0);

         for(int i=1;i<=n;i++)//查询0-i-1之间比a[i]小的数放在lmin[i]里,在i-m之间比a[i]大的放在lmax里

         {

             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\n",ans);

    }

    return 0;

}

posted @ 2016-08-07 11:55  幻世沉溺  阅读(115)  评论(0编辑  收藏  举报