题目大意:

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的加和,然后求某一个区间的话就是相减,没有任何问题,而且对于树状数组维护的东西又有了较为深刻的认识(可以把其他的值一转化来维护);

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

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

代码如下:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5.  
  6. using namespace std;
  7.  
  8. typedef long long ll;
  9.  
  10. const int maxn = +;
  11. int max_[maxn],min_[maxn],hmin_[maxn],hmax_[maxn];
  12. int num[maxn],a[maxn],b[maxn],sum[maxn];
  13. ll res;
  14. int n,m;
  15.  
  16. int lowbit(int x)
  17. {
  18. return x&(-x);
  19. }
  20.  
  21. void add(int x)
  22. {
  23. while(x<=m)
  24. {
  25. num[x]++;
  26. x+=lowbit(x);
  27. }
  28. }
  29.  
  30. int query(int x)
  31. {
  32. int ans=;
  33. while(x>=)
  34. {
  35. ans+=num[x];
  36. x-=lowbit(x);
  37. }
  38. return ans;
  39. }
  40.  
  41. int main()
  42. {
  43. while(scanf("%d",&n)==)
  44. {
  45. for(int i=;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
  46. sort(b+,b+n+);
  47. m=unique(b+,b+n+)-(b+);
  48. for(int i=;i<=n;i++) a[i]=lower_bound(b+,b+m+,a[i])-b;
  49. memset(num,,sizeof(num));
  50. memset(sum,,sizeof(sum));
  51. for(int i=;i<=n;i++)
  52. {
  53. min_[i]=query(a[i]-);
  54. max_[i]=query(m)-query(a[i]);
  55. sum[i]=sum[i-]+min_[i];
  56. add(a[i]);
  57. }
  58. memset(num,,sizeof(num));
  59. for(int i=n;i>=;i--)
  60. {
  61. hmin_[i]=query(a[i]-);
  62. hmax_[i]=query(m)-query(a[i]);
  63. add(a[i]);
  64. }
  65. res=;
  66. ll num1,num2;
  67. for(int i=;i<=n;i++)
  68. {
  69. num1=max_[i];
  70. num2=sum[n];
  71. res+=num1*num2;
  72. }
  73. //a=c&&b!=d;
  74. for(int i=;i<=n;i++)
  75. {
  76. num1=hmin_[i];
  77. num2=hmax_[i];
  78. res-=num1*num2;
  79. }
  80. //a!=c&&b=d;
  81. for(int i=;i<=n;i++)
  82. {
  83. num1=min_[i];
  84. num2=max_[i];
  85. res-=num1*num2;
  86. }
  87. //a=d&&b!=c;
  88. for(int i=;i<=n;i++)
  89. {
  90. num1=max_[i];
  91. num2=hmax_[i];
  92. res-=num1*num2;
  93. }
  94. //a!=d&&b=c;
  95. for(int i=;i<=n;i++)
  96. {
  97. num1=hmin_[i];
  98. num2=min_[i];
  99. res-=num1*num2;
  100. }
  101. printf("%I64d\n",res);
  102. }
  103. return ;
  104. }

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. Java集合类里面最基本的接口

    Collection:代表一组对象,每一个对象都是它的子元素. Set:不包含重复元素的Collection. List:有顺序的Collection,并且可以包含重复元素. Map:可以把键(key ...

  2. 致第一次安装(yong)小小输入法的你

    目录 强大全开放的外挂内置输入平台 支持各种编码 方便的词库维护功能 最温情的输入法 小鹤双拼自定义 本文的题目就参考了百度贴吧「致第一次安装 RIME 的你」,因为最近使用小小输入法,感觉很好用,所 ...

  3. springcloud中provider-product依赖

    <dependencies> <dependency> <groupId>cn.lijun.springcloud</groupId> <arti ...

  4. 【Beta阶段】第十一次Scrum Meeting!

    第十一周会议记录 [Beta阶段]第十一次Scrum Meeting! 一.每日任务内容 本次会议为第十一次Scrum Meeting会议~ 本次会议主要探讨了各自进展以及后续要继续开展的工作. 小组 ...

  5. SQL取日期部分的方法

    一.convert convert(varchar(10),getdate(),120)   :  varchar(10) 截取位数可以调节,最多能显示19位(varchar(19)) 如:2009- ...

  6. Eclipse ALT+/ 代码没有提示功能

    第一种配置如下: 第二: 第三: 以上三种方式是关于eclipse代码提示

  7. Python3中 if __name__=='__main__'是个什么意思

    在python前期学习中或者在学flask中,if_name_ = ="_main_"经常出现在我们的眼帘中,我们经常会问,这个是个什么玩意儿,它是干什么的? 我们知道,if 语句 ...

  8. Insmod模块加载过程分析

    一.背景 a) 在进行JZ2440的一个小demo开发的时候,使用自己编译的内核(3.4.2)及lcd模块进行加载时,insmod会提示加载失败因为内核版本不匹配(提示当前内核版本为空),并且显示模块 ...

  9. grep 后加单引号、双引号和不加引号的区别

    请尊重版权,原文地址:https://blog.csdn.net/cupidove/article/details/8783968 单引号: 可以说是所见即所得:即将单引号内的内容原样输出,或者描述为 ...

  10. SQL 测验题目(30道)

    1.SQL 指的是? 您的回答:Structured Query Language 2.哪个 SQL 语句用于从数据库中提取数据? 您的回答:SELECT 3.哪条 SQL 语句用于更新数据库中的数据 ...