洛谷P1637 三元上升子序列

P1637 三元上升子序列

  • 48通过
  • 225提交
  • 题目提供者该用户不存在
  • 标签云端
  • 难度提高+/省选-
  • 时空限制1s / 128MB

提交  讨论  题解

最新讨论更多讨论

  • 为什么超时啊
  • a的数据比较大啊,真的能用…

题目描述

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

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

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

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

输入输出格式

输入格式:

开始一个正整数n,

以后n个数a1~an。

输出格式:

"thair"的个数

输入输出样例

输入样例#1

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

分析:这道题可以借鉴之前求逆序对那样求,我们只需要求对于每一个数i,在i之前比i小的数的个数和在i之后比i大的数的个数,相乘起来,最后将所有结果加起来就是答案,关键就是如何求出这些数的个数。可以利用树状数组。先将数据离散化,先找小于i的,因为要严格小于,所以我们要先-1再查找,然后添加进去,然后找大于i的,从后往前枚举,相当于我们找到i之后不大于i的个数,然后用n-i(i之后的数的个数)减去结果就是严格大于i的数的个数,最后统计一下答案即可。

如果将这道题推广到要找k个数的情况,我们需要用到dp,则dp[i][j] = dp[k][j-1] + dp[k][j],其中k为小于i中最靠后的一个数.

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>

using namespace std;

long long d1[30010], d2[30010],ans1[30010],ans2[30010],dis[30010],ans;

struct node
{
    long long v;
    int id;
}a[30010];

int n;

void update(long long x, int v)
{
    while (x <= n)
    {
        d1[x] += v;
        x += x &(-x);
    }
}

int sum(long long x)
{
    int cnt = 0;
    while (x)
    {
        cnt += d1[x];
        x -= x & (-x);
    }
    return cnt;
}

void update2(long long x, int v)
{
    while (x <= n)
    {
        d2[x] += v;
        x += x &(-x);
    }
}

int sum2(long long x)
{
    int cnt = 0;
    while (x)
    {
        cnt += d2[x];
        x -= x & (-x);
    }
    return cnt;
}

bool cmp(node a, node b)
{
    return a.v < b.v;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i].v);
        a[i].id = i;
    }
    sort(a + 1, a + 1 + n, cmp);
    dis[a[1].id] = 1;
    int tot = 1;
    for (int i = 2; i <= n; i++)
    {
        if (a[i].v != a[i - 1].v)
            tot++;
        dis[a[i].id] = tot;
    }
    for (int i = 1; i <= n; i++)
    {
        ans1[i] = sum(dis[i] - 1); //是找严格小于的而不是小于等于的
        update(dis[i], 1);
    }
    for (int i = n; i >= 1; i--)
    {
        ans2[i] = n - i - sum2(dis[i]);
        update2(dis[i], 1);
    }
    for (int i = 1; i <= n; i++)
        ans += ans1[i] * ans2[i];
    printf("%lld\n", ans);

    return 0;
}
时间: 2024-11-08 11:04:34

洛谷P1637 三元上升子序列的相关文章

洛谷P2766-最长递增子序列问题

chunlvxiong的博客 题目描述: 给定正整数序列x1,...,xn (1≤n≤500). 1.计算其最长递增子序列的长度s. 2.计算从给定的序列中最多可取出多少个长度为s的递增子序列. 3.如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列. 思考&分析:  第一问应该比较easy,利用DP求解,时间复杂度O(N^2)--利用线段树可以优化到O(NlogN),但是没这个必要. 第二问:考虑使用网络流求解. 首先把所有点x拆成两个点xa,xb,每

Luogu P1637 三元上升子序列【权值线段树】By cellur925

题目传送门 emmm..不开结构体的线段树真香! 首先我们知道"三元上升子序列"的个数就是对于序列中的每个数,**它左边比他小的数*它右边比他大的数**.但是如何快速求出这两个数? 我们用到权值线段树来维护.一般我们的线段树都是以下标延伸的,但是这里我们用的是权值,一般需要离散化,效果相当于一个桶. 这部分讲解请移步绝世好文 第一次我们从\(1\)~\(n\)循环是为了找它左边的,而找比他小的值是在线段树的\(1\)~\(seq[i]-1\)中找.第二次我们从\(n\)~\(1\)循环

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

洛谷 P1439 【模板】最长公共子序列

神TM模板..我本来想休闲一下写点水题的... 开始做的时候直接敲了一个O(N2)的算法上去,编译的时候才发现根本开不下.. 好了,谈回这道题. 先不加证明的给出一种算法. 若有一组数据 2 4 2 5 1 3 2 5 4 1 3 那么我们令 4 2 5 1 3 | | | | | 1 2 3 4 5 第三行的数据就变成 2 3 1 4 5 很明显,答案是这个数据的最长上升子序列,即4 == 2 3 4 5,即原数列的2 5 1 3. 现在来大概的介绍一下这样做的原因. 首先,观察题目,注意到这

洛谷P1122 最大子树和 树形DP

洛谷P1122 最大子树和一道类似树形DP 的题目 首先我们随意定根 ,假设我们定根为 1, 那么我们设dp[ i ] 表示 在这个整个以1为根的树中 以 i为根的子树 i 这个点强制取到 , 我们再从他的子树中取出一部分出来,最大能够取到的和 我们可知 当 枚举到dp[ u ] 时 ,我们看他的儿子取不取 如果v是它的儿子 若dp[ v ] > 0 那么我们就取 ,否则就不取,取了反而会减少 这样类似最长连续子序列一样就行了 然后类似树形DP 一样从根节点向根扩展就行了 ,也就是dfs下去 然

洛谷P1198 [JSOI2008]最大数

P1198 [JSOI2008]最大数 267通过 1.2K提交 题目提供者该用户不存在 标签线段树各省省选 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 WA80的戳这QwQ BZOJ都过了,洛谷竟然过不了… 为什么过不了 = =我想说这题加优读会WA?… 谁说pascal只能80,要换c++… 线段树为什么是80? 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超

【模板】LIS模板 洛谷P1091 [NOIP2004提高组]合唱队形 [2017年4月计划 动态规划11]

以题写模板. 写了两个:n^2版本与nlogn版本 P1091 合唱队形 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<...<Ti>Ti+1>…>TK(1<=i<=K). 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形. 输入输出格

[洛谷OJ] P1114 “非常男女”计划

洛谷1114 “非常男女”计划 本题地址:http://www.luogu.org/problem/show?pid=1114 题目描述 近来,初一年的XXX小朋友致力于研究班上同学的配对问题(别想太多,仅是舞伴),通过各种推理和实验,他掌握了大量的实战经验.例如,据他观察,身高相近的人似乎比较合得来. 万圣节来临之际,XXX准备在学校策划一次大型的“非常男女”配对活动.对于这次活动的参与者,XXX有自己独特的选择方式.他希望能选择男女人数相等且身高都很接近的一些人.这种选择方式实现起来很简单.

BZOJ 4385 洛谷3594 POI2015 WIL-Wilcze do?y

[题解] 手残写错调了好久QAQ...... 洛谷的数据似乎比较水.. n个正整数!!这很重要 这道题是个类似two pointer的思想,外加一个单调队列维护当前区间内长度为d的子序列中元素之和的最大值. 枚举右端点,如果左端点到右端点的元素和减去区间内长为d的子序列中元素和的最大值,大于给定的P,那么就把左端点向右挪. #include<cstdio> #include<algorithm> #define N 2000010 #define rg register #defi