P1637 三元上升子序列

题目描述

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

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

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

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

输入输出格式

输入格式:

 

开始一个正整数n,

以后n个数a1~an。

 

输出格式:

 

"thair"的个数

 

输入输出样例

输入样例#1: 复制

4
2 1 3 4

输出样例#1: 复制

2

输入样例#2: 复制

5
1 2 2 3 4

输出样例#2: 复制

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 约定 30%的数据n<=100

60%的数据n<=2000

100%的数据n<=30000

大数据随机生成

0<=a[i]<=maxlongint

思路:首先看到这个题我们很容易的想到枚举每一个数,然后用该数左边比他小的数的个数乘以该数右边比他大的数的个数,然后将所有的结果相加即可,但是在这里因为他给的是大数据随机生成,所以我们按一般的方法来写是不可行的,例如他给出999999999,那么我们就需要一个数组List【999999999】,显然不存在,所以就有了离散化的方法,我们不需要开这么大的数组,我们只需要记住他们之间的大小便可以用其他数来替代,例如520,9999999,18,666,88888我们可以用2,5,1,3,4来替代,这样我们开的数组的范围就小了很多,其他的就看代码吧,具体内容在代码里进行讲解

#include<iostream>
#include<algorithm>
using namespace std;
#define lowbit(i) ((i) & (-i))
const int maxn = 30010;
struct Node{
    int val;
    int pos;
}node[maxn];
int cmp(Node e, Node f) {
    return e.val < f.val;
}
long long n, a, ans;
int c[maxn], numGreater[maxn], numLess[maxn], List[maxn];

void update(int x) {
    for (int i = x; i < maxn; i += lowbit(i)) {
        c[i] += 1;
    }
}

long long getSum(int x) {
    long long sum = 0;
    for (int i = x; i > 0; i -= lowbit(i)) {
        sum += c[i];
    }
    return sum;
}
int main () {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> node[i].val;
        node[i].pos = i;
    }
   //离散化
    sort (node + 1, node + 1 + n, cmp); //按照值从大到小排序
    for (int i = 1; i <= n; i++) {
         //与上一个元素不同时,赋值为元素个数
        if (i == 1 || node[i].val != node[i - 1].val) {
            List[node[i].pos] = i;
        } else {
            //相同时直接继承
            List[node[i].pos] = List[node[i - 1].pos];
        }
    }
    //求该数左边比他小的数的个数
    for (int i = 1; i <= n; i++) {
        update(List[i]);
        numLess[i] = getSum(List[i] - 1);
    }
    //必须要重置,因为后面还会用到
    fill(c + 1, c + n + 1, 0);
    //求该数右边比他大的数的个数,我们倒这来一遍就可以了
    for (int i = n; i > 0; i--) {
        update(List[i]);
        numGreater[i] = n - i + 1 - getSum(List[i]);
    }
    //左边比他小的数的个数乘以右边比他大的数的个数
    for (int i = 2; i < n; i++) {
        ans += numLess[i] * numGreater[i];
    }
    cout << ans << endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值