HDU-5792

点击打开题目链接

World is Exploding

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

题意很明确,就是让我们求一个四元组,满足 a<b并且c<d.
解题思路:可以求出所有的四元组数目减去不符合条件四元组的数目,就可以得到我们需要的了。具体怎么实现呢,做这个题顺便学习了一下树状数组(百度百科有很详细的解释),真是很神奇的东西。但是这道题确实让我转了很大的圈子。具体解释详见代码。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
long long a[50001],b[50001],c[50001],aa[50001];
long long yx[50001],yd[50001],zx[50001],zd[50001];
long long n;
long long num; // 这里全部用 long long 是为了省事儿 
long long get_k(long long k)
{
	return k&-k;
}
void add(long long pos,long long val)
{
	while(pos<=n)
	{
		c[pos] += val; // 数组c是用来存储树状数组的值 
		pos += get_k(pos);
	}
	return ;
}
long long get_sum(long long pos)
{
	long long ans = 0;
	while(pos>0)
	{
      	ans += c[pos];
      	pos -= get_k(pos);
	}
   return ans;
}   // 以上三个函数为对树状数组的操作 ,百度百科可以很详细的学习树状数组。 
int main()
{
    while(scanf("%lld",&n)!=EOF)
    {
	memset(c,0,sizeof(c));
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(yx,0,sizeof(yx));
	memset(yd,0,sizeof(yd));
	memset(zx,0,sizeof(zx));
	memset(zd,0,sizeof(zd)); 
	for(int i=1;i<=n;i++)
	{
		scanf("%lld", &a[i]);
		b[i] = a[i];
	}
	
	sort(b+1,b+1+n);
    num = unique(b+1,b+1+n) - (b+1); //排序去重,方便离散化,其实这一步有没有都能AC。 
    
    long long sum1,sum2;
    sum1 = sum2 = 0;
    //两个for循环,正反各一次 
	for(int i=1;i<=n;i++)  
	{
		long long pos = lower_bound(b+1,b+1+num,a[i]) - b; // 每次找到a[i]的位置,如果没用unique,num就改为n 
		add(pos,1);
		zx[i] =  get_sum(pos-1); //左边比a[i]小的数目 
		zd[i] =  i - get_sum(pos);//左边比a[i]大的数目 
	}
	
   memset(c,0,sizeof(c)); // 反向循环的时候树状数组要清空重建 
	
   for(int i=n; i>=1; i--)
   {
   	    long long pos = lower_bound(b+1,b+1+n,a[i]) - b;
   	    add(pos,1);
   	    yx[i] = get_sum(pos-1);   //  右边比a[i]小的数目 
   	    yd[i] = n-i+1 - get_sum(pos); //右边比a[i]大的数目  
   	    sum1 += yx[i];
		sum2 += yd[i];
	}
	
   long long pp = sum1 * sum2; // 所有的四元组 
   
   /*重复的情况有四种
    即 ac重复,ad重复,bc重复,bd重复  
    */ 
   for(int i=1;i<=n;i++)
   {
	 pp -= zx[i]*yx[i];
	 pp -= zd[i]*yd[i];
	 pp -= zx[i]*zd[i];
	 pp -= yx[i]*yd[i];	
   }	
   printf ("%lld\n",pp);
  }
	
	
	return 0;
}

水波








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值