• 洛谷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
    ", ans);
    
        return 0;
    }
  • 相关阅读:
    python manage.py runserver 127.0.0.1:8000 启动后台有两个启动进程
    python3 异步任务之----celery
    @property、@staticmethod、@classmethod装饰器
    python工具类之collections
    面试编程题TEG
    python字符串相关操作
    python 时间操作
    防止恶意调用
    python
    gdb可以调试python的pdb么
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7078292.html
Copyright © 2020-2023  润新知