题目描述

Erwin最近对一种叫"thair"的东西巨感兴趣。。。

在含有n个整数的序列a1,a2......an中,

三个数被称作"thair"当且仅当i<j<k且ai<aj<ak

求一个序列中"thair"的个数。

输入输出格式

输入格式:

开始一个正整数n,

以后n个数a1~an。

输出格式:

"thair"的个数

输入输出样例

输入样例#1:

4 50 18
3
4
6
8
14
15
16
17
21
25
26
Input
4
2 1 3 4
Output
2
Input
5
1 2 2 3 4
Output
7
对样例2的说明:
7个"thair"分别是
1 2 3
1 2 4
1 2 3
1 2 4
1 3 4
2 3 4
2 3 4
输出样例#1:


说明

约定 30%的数据n<=100

60%的数据n<=2000

100%的数据n<=30000

大数据随机生成

0<=a[i]<=maxlongint

那么如果我们考虑在输入时考虑当前的c,那么我们只需找两个小于c并且不同的数

如果位置小于c且值小于c的数没有重复,那么我们可以得到是,以c结尾的三元组数量是

n*(n-1)/2,

有重复元素怎么办呢,因为这样计数,1,2,2,3,4,计算以4结尾的三元组时,会算到2,2,4

那么怎么解决这个问题..

解决1:

换种计数方法,考虑中间元素b,我们只需考虑b之前有多少个严格小于它的元素数量u,之后有多少严格大于它的元素v

于是中间元素b的三元组对答案的贡献就是u*v

于是我们可以算两遍,第一遍算u第二遍算v

附上代码...

 1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 using namespace std;
6 const int maxn=1e5+7;
7 int N,w;
8 typedef long long ll;
9 ll t[maxn],u[maxn],v[maxn];
10 struct node{
11 int id,v;node(){};node(int id,int v):id(id),v(v){};
12 };
13 node a[maxn];
14 int lowbit(int x){
15 return x&-x;
16 }
17 void add(int n,int x){
18 while(n<=N){
19 t[n]+=x;
20 n+=lowbit(n);
21 }
22 }
23 int sum(int n){
24 int ans=0;
25 while(n){
26 ans+=t[n];
27 n-=lowbit(n);
28 }
29 return ans;
30 }
31 bool cmp1(node a,node b){
32 return a.v<b.v;
33 }
34 bool cmp2(node a,node b){
35 return a.id<b.id;
36 }
37 int main(){
38 int n,x;scanf("%d",&n);
39 for(int i=1;i<=n;++i){
40 scanf("%d",&x);
41 a[i]=node(i,x);
42 }
43 sort(a+1,a+1+n,cmp1);
44 int cnt=1,st=1,pre=a[1].v;
45 for(int i=2;i<=n;++i){
46 while(i<=n&&a[i].v==pre) i++;
47 for(int j=st;j<i;++j){
48 a[j].v=cnt;
49 }
50 st=i;pre=a[i].v;
51 cnt++;
52 }
53 for(int j=st;j<=n;++j) a[j].v=cnt;
54 //for(int i=1;i<=n;++i) printf("%d,",a[i].v);printf("\n");
55 N=cnt;
56 sort(a+1,a+1+n,cmp2);
57 ll ans=0;
58 for(int i=1;i<=n;++i){
59 u[i]=sum(a[i].v-1);
60 add(a[i].v,1);
61 }
62 memset(t,0,sizeof(t));
63 for(int i=n;i>=1;--i){
64 v[i]=sum(N)-sum(a[i].v);
65 ans+=u[i]*v[i];
66 add(a[i].v,1);
67 }
68 printf("%lld\n",ans);
69 return 0;
70 }

其实也可以这么写,

因为sum(N)=n-i的,因为是倒着插入的,所以当你插入n时,正好已经插入了n-n个元素,

插入n-1时,正好已经插入了一个元素,所以n-i-sum(a[i].v)的意思是,当前插入的所有元素减去小于等于v的元素个数,

那么剩下的一定都大于v,sum(N)=大于v的元素个数+小于等于v的元素个数

 1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 using namespace std;
6 const int maxn=1e5+7;
7 int N,w;
8 typedef long long ll;
9 ll t[maxn],u[maxn],v[maxn];
10 struct node{
11 int id,v;node(){};node(int id,int v):id(id),v(v){};
12 };
13 node a[maxn];
14 int lowbit(int x){
15 return x&-x;
16 }
17 void add(int n,int x){
18 while(n<=N){
19 t[n]+=x;
20 n+=lowbit(n);
21 }
22 }
23 int sum(int n){
24 int ans=0;
25 while(n){
26 ans+=t[n];
27 n-=lowbit(n);
28 }
29 return ans;
30 }
31 bool cmp1(node a,node b){
32 return a.v<b.v;
33 }
34 bool cmp2(node a,node b){
35 return a.id<b.id;
36 }
37 int main(){
38 int n,x;scanf("%d",&n);
39 for(int i=1;i<=n;++i){
40 scanf("%d",&x);
41 a[i]=node(i,x);
42 }
43 sort(a+1,a+1+n,cmp1);
44 int cnt=1,st=1,pre=a[1].v;
45 for(int i=2;i<=n;++i){
46 while(i<=n&&a[i].v==pre) i++;
47 for(int j=st;j<i;++j){
48 a[j].v=cnt;
49 }
50 st=i;pre=a[i].v;
51 cnt++;
52 }
53 for(int j=st;j<=n;++j) a[j].v=cnt;
54 //for(int i=1;i<=n;++i) printf("%d,",a[i].v);printf("\n");
55 N=cnt;
56 sort(a+1,a+1+n,cmp2);
57 ll ans=0;
58 for(int i=1;i<=n;++i){
59 u[i]=sum(a[i].v-1);
60 add(a[i].v,1);
61 }
62 memset(t,0,sizeof(t));
63 for(int i=n;i>=1;--i){
64 v[i]=n-i-sum(a[i].v);
65 ans+=u[i]*v[i];
66 add(a[i].v,1);
67 }
68 printf("%lld\n",ans);
69 return 0;
70 }

洛谷p1637 三元上升子序列(树状数组的更多相关文章

  1. 洛谷P1637 三元上升子序列

    P1637 三元上升子序列 48通过 225提交 题目提供者该用户不存在 标签云端 难度提高+/省选- 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 为什么超时啊 a的数据比较 ...

  2. [洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?

    其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数 ...

  3. 洛谷P3688/uoj#291. [ZJOI2017]树状数组

    传送门(uoj) 传送门(洛谷) 这里是题解以及我的卡常数历程 话说后面那几组数据莫不是lxl出的这么毒 首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间 ...

  4. 洛谷P3368 【模板】树状数组 2

    P3368 [模板]树状数组 2 102通过 206提交 题目提供者HansBug 标签 难度普及/提高- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 如题,已知一个数列,你需要进行下面两 ...

  5. 洛谷P3374 【模板】树状数组 1

    P3374 [模板]树状数组 1 140通过 232提交 题目提供者HansBug 标签 难度普及/提高- 提交  讨论  题解 最新讨论 题目描述有误 题目描述 如题,已知一个数列,你需要进行下面两 ...

  6. 洛谷 P3368 【模板】树状数组 2

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  7. 洛谷 P3374 【模板】树状数组 1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  8. 树状数组模板(pascal) 洛谷P3374 【模板】树状数组1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  9. 洛谷 P3368 【模板】树状数组 2(区间修改点查询)

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

随机推荐

  1. scrapy的大文件下载(基于一种形式的管道类实现)

    scrapy的大文件下载(基于一种形式的管道类实现) 爬虫类中将解析到的图片地址存储到item,将item提交给指定的管道 在管道文件中导包:from scrapy.pipelines.images ...

  2. jmeter-并发及常数吞吐量定时器设定

  3. Vue基础之插值表达式的另一种用法!附加变量的监听!

    Vue基础之插值表达式的另一种用法!附加变量的监听! 讲这个之前我们先回顾一下原来的用法! <body> <!-- Vue.js的应用可以分为两个重要的组成部分 一个是视图! 另一个 ...

  4. Java并发包源码学习系列:阻塞队列实现之LinkedBlockingQueue源码解析

    目录 LinkedBlockingQueue概述 类图结构及重要字段 构造器 出队和入队操作 入队enqueue 出队dequeue 阻塞式操作 E take() 阻塞式获取 void put(E e ...

  5. Java int和integer有什么区别 (mybatis踩坑)

    不要在实体类中使用int 我们都知道Integer是int的包装类,而int是基本数据类型.所以Integer类型的变量会初始化为null,int类型则会被初始化为0 . 所以在下面的动态拼接例子中: ...

  6. SpringCloud及其组件详解

    SpringCloud及其组件详解 1.Spring Cloud 1.1 Spring Cloud和Dubbo的区别图解 1.2 微服务的技术栈 2.Spring Cloud 概述 2.1 Sprin ...

  7. NFS服务、SSHD服务

    本章内容: NFS服务 SSHD服务 NFS服务 NFS(Network File System)即网络文件系统,用以在网络上与他人共享文件和目录:NFS是运行在应用层的协议:基于Client/Ser ...

  8. Git实践笔记(一)

    Git是什么 Git是目前世界上最先进的分布式版本控制系统. 工作原理 / 流程: Workspace:工作区 Index / Stage:暂存区 Repository:仓库区(或本地仓库) Remo ...

  9. Flink-v1.12官方网站翻译-P006-Intro to the DataStream API

    DataStream API介绍 本次培训的重点是广泛地介绍DataStream API,使你能够开始编写流媒体应用程序. 哪些数据可以流化? Flink的DataStream APIs for Ja ...

  10. Java排序算法(四)希尔排序1

    希尔排序交换法:分组+冒泡排序组合 一.测试类SortTest import java.util.Arrays; public class SortTest { private static fina ...