题目大意:

Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ada≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad.

A1,A2⋯AnA1,A2⋯An.  1≤n≤500001≤n≤50000  0≤Ai≤1e9

基本思路:

最朴素的思想就是算出所有顺序对所有逆序对相乘然后再减去所有有重复元素的结果,最终得到答案;

将原数组排序后去重然后从1开始标号(离散化),然后线段树维护某个标号有多少个数;

min_[i]:表示原数组下标在1~i-1的数比下标为i的数小的数的个数;

max_[i]:表示原数组下标在1~i-1的数比下标为i的数大的数的个数;

hmin_[i]:表示原数组下标在i之后的数比下标为i的数小的数的个数;

hmax_[i]:表示原数组下标在i之后的数比下标为i的数大的数的个数;

num[i]:树状数组的维护数组;

sum[i]:表示到下标为i的数中,从中任意挑出两个数满足下标小的数小于下标大的数的个数;

接下来枚举当前ai作为Vd,那么就存在mx[i]个Vc,以及sum[n]对Va,Vb。res+=mx[i]*sum[n]

由于答案会多算进去a=c || a=d || b=c || b=d的情况,那么枚举这四种情况减去就可以了,a=c那么必定b!=d,同理其他

a=c:ans-=hmn[i]*hmx[i]

a=d:ans-=mx[i]*hmx[i]

b=c:ans-=mn[i]*hmn[i]

b=d:ans-=mx[i]*mn[i]

反思与总结:

//对于树状数组,我一直有所顾忌,因为就比如num【4】的值并不加和在num【6】里,其实没必要了,因为树状数组用到的操作就是求和和求最大最小值,然后求和的话并不是直接用这些数组元素,而是一个模板函数去求,这个函数求出来的就是1~i的加和,然后求某一个区间的话就是相减,没有任何问题,而且对于树状数组维护的东西又有了较为深刻的认识(可以把其他的值一转化来维护);

//以后的话可以将某些对象抽象,从抽象层面考虑问题,也许问题会变得更容易想,这就是教主说的改变思维方式吧,走出思维的舒适区;

//我还发现对于一个对象在一个程序中,可以分别赋予多种抽象,前提是一个用完之后再用另一个不能混着来;

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; typedef long long ll; const int maxn = +;
int max_[maxn],min_[maxn],hmin_[maxn],hmax_[maxn];
int num[maxn],a[maxn],b[maxn],sum[maxn];
ll res;
int n,m; int lowbit(int x)
{
return x&(-x);
} void add(int x)
{
while(x<=m)
{
num[x]++;
x+=lowbit(x);
}
} int query(int x)
{
int ans=;
while(x>=)
{
ans+=num[x];
x-=lowbit(x);
}
return ans;
} int main()
{
while(scanf("%d",&n)==)
{
for(int i=;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+,b+n+);
m=unique(b+,b+n+)-(b+);
for(int i=;i<=n;i++) a[i]=lower_bound(b+,b+m+,a[i])-b;
memset(num,,sizeof(num));
memset(sum,,sizeof(sum));
for(int i=;i<=n;i++)
{
min_[i]=query(a[i]-);
max_[i]=query(m)-query(a[i]);
sum[i]=sum[i-]+min_[i];
add(a[i]);
}
memset(num,,sizeof(num));
for(int i=n;i>=;i--)
{
hmin_[i]=query(a[i]-);
hmax_[i]=query(m)-query(a[i]);
add(a[i]);
}
res=;
ll num1,num2;
for(int i=;i<=n;i++)
{
num1=max_[i];
num2=sum[n];
res+=num1*num2;
}
//a=c&&b!=d;
for(int i=;i<=n;i++)
{
num1=hmin_[i];
num2=hmax_[i];
res-=num1*num2;
}
//a!=c&&b=d;
for(int i=;i<=n;i++)
{
num1=min_[i];
num2=max_[i];
res-=num1*num2;
}
//a=d&&b!=c;
for(int i=;i<=n;i++)
{
num1=max_[i];
num2=hmax_[i];
res-=num1*num2;
}
//a!=d&&b=c;
for(int i=;i<=n;i++)
{
num1=hmin_[i];
num2=min_[i];
res-=num1*num2;
}
printf("%I64d\n",res);
}
return ;
}

hdu 5792 树状数组+离散化+思维的更多相关文章

  1. hdu 5792(树状数组,容斥) World is Exploding

    hdu 5792 要找的无非就是一个上升的仅有两个的序列和一个下降的仅有两个的序列,按照容斥的思想,肯定就是所有的上升的乘以所有的下降的,然后再减去重复的情况. 先用树状数组求出lx[i](在第 i ...

  2. HDU 1394 树状数组+离散化求逆序数

    对于求逆序数问题,学会去利用树状数组进行转换求解方式,是很必要的. 一般来说我们求解逆序数,是在给定一串序列里,用循环的方式找到每一个数之前有多少个比它大的数,算法的时间复杂度为o(n2). 那么我们 ...

  3. [hdu 4417]树状数组+离散化+离线处理

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 把数字离散化,一个查询拆成两个查询,每次查询一个前缀的和.主要问题是这个数组是静态的,如果带修改 ...

  4. Disharmony Trees HDU - 3015 树状数组+离散化

    #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using ...

  5. hdu 4325 树状数组+离散化

    思路:这题的思路很容易想到,把所有时间点离散化,然后按时间一步一步来,当到达时间i的时候处理所有在i处的查询. 这个代码怎一个挫字了得 #include<iostream> #includ ...

  6. Swaps and Inversions HDU - 6318 树状数组+离散化

    #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> us ...

  7. C - The Battle of Chibi HDU - 5542 (树状数组+离散化)

    Cao Cao made up a big army and was going to invade the whole South China. Yu Zhou was worried about ...

  8. hdu 4638 树状数组 区间内连续区间的个数(尽可能长)

    Group Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  9. hdu 4777 树状数组+合数分解

    Rabbit Kingdom Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

随机推荐

  1. Vector、ArrayList、LinkedList、CopyOnWriteArrayList区别

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11443907.html CopyOnWriteArrayList CopyOnWriteArrayLi ...

  2. Java中的多表&事务&DCL&一个多表操作例子

    准备sql: 创建部门表 CREATE TABLE dept( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO d ...

  3. 深入理解java虚拟机:笔记

    1.运行时数据区域 1.程序计数器 当前线程执行字节码的行号指示器,字节码解释器工作通过改变这个计数器的值来选取下一条需要执行的字节码指令,每一个线程拥有独立的程序计数器,线程私有的内存 2.虚拟机栈 ...

  4. 【leetcode】990. Satisfiability of Equality Equations

    题目如下: Given an array equations of strings that represent relationships between variables, each strin ...

  5. C/C++ C++ 11 std::move()

    { 0. C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意 是想把参数push_back进去就行 ...

  6. make编写教程(二)

    1. make中的变量 makefile中的变量就是c/c++中的宏 2. 引用其他的make文件 类似于c语言中的#include,被包含的文件会原模原样的放在当前文件的包含位置. include& ...

  7. UNP学习第六章select

    一.I/O复用典型的网络应用场合 当客户处理多个描述字时,必须使用I/O复用,这在前一段中已做了描述. 一个客户同时处理多个套接口时可能的,但很少出现. 如果一个TCP服务器既要处理监听套接口,又要处 ...

  8. H5页面前后端通信 (3种方式简单介绍)

    1.ajax:短连接 2.websocket :长连接,双向的.   node搭建的websocket服务器,推送信息给客户端浏览器 :https://www.cnblogs.com/fps2tao/ ...

  9. 用 Flask 来写个轻博客 (11) — M(V)C_创建视图函数

    目录 目录 前文列表 视图函数 在 viewspy 文件中定义视图函数 定义右侧边栏的视图函数 为每一张数据表定义视图函数 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask ...

  10. expand gcc case variable length

    daniel@daniel-mint ~/vex $ bash gen.sh 0x10 0x1F case 10: case 11: case 12: case 13: case 14: case 1 ...