zoukankan      html  css  js  c++  java
  • 树状数组 P1966 火柴排队【逆序对】

    题目

    https://www.luogu.com.cn/problem/P1966

    题目分析

    1.求两列之间的距离最小值:其实就是要求a 序列第 k 大的元素必须和序列 b 中第k大的元素的位置必须一样(通俗的讲就是aj与bj大的对应大的,小的对应小的,这样相减的平方和才最小)
    2.火柴高度范围是2的31次方,如果直接进行运算数组会超,所以这里需要离散化,用id来表示数字大小。
    3.现在得到两个id数组,答案就是A序列不动,B序列变为A序列需要与相邻元素交换几次。
    4.计算步骤3的方法就是使用一个数组Q,令 q[a[i]] = b[i] ,相当于以 a[i] 为关键字对序列 b[i] 排序。
    5.排序移动的次数其实就是序列Q中的逆序对的和。

    以题目中的输入一为例:

    A:  2 3 1 4

    A下标:1 2 3 4

    B:  3 2 1 4

    B下标:1 2 3 4


     再以数字的值排序后:

    A:  1 2 3 4

    A下标:3 1 2 4

    B:  1 2 3 4

    B下标:3 2 1 4


     令 q[a[i]] = b[i] (这里a[]为A下标,b[]为B下标)

    A下标:3 1 2 4

    B下标:3 2 1 4

    q[3]=3  q[1]=2  q[2]=1  q[4]=4;

    对应代码中的:

    for (int i = 1; i <= n; i++)
            q[a[i].id] = b[i].id;

    对Q数组的下标整理为从小到大:(这里的思路理解其实是下标:即a[]数组,排序为从小到大,而对应的值:b[]数组也跟着排了,两个数组一起变化,步骤是不变的,也就是对答案不影响,但是a[]数组变得有序了,现在只要让b[]数组有序,计算从此刻开始到有序的步骤既是答案 这样做比双方未排序前,直接计算b[]变为a[]需要的步骤更简单可实现

    q[1]=2  q[2]=1  q[3]=3  q[4]=4;

    值序列为2 1 3 4

    则2 1 3 4的逆序列和即为答案:1

    对应代码中的:(这就是逆序对的知识了,不再赘述)

    for (int i = 1; i <= n; i++)
        {
            update(q[i], 1);//i从小到大的顺序进行update
            answer += i - getsum(q[i]);//用来存储原数第i个数的order下标是什么
        }

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct node
    {
        long long val;
        int id;
    }a[100005],b[100005];
    long long c[100005],c2[100005];
    int q[100005];
    int n;
    bool cmp(struct node &a, struct node&b)
    {
        if (a.val == b.val)return a.id < b.id;
        return a.val < b.val;
    }
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int i, int k)
    {
        while (i <= n)
        {
            c[i] += k;
            i += lowbit(i);
        }
    }
    long long getsum(int i)
    {
        long long res = 0;
        while (i > 0)
        {
            res += c[i];
            i -= lowbit(i);
        }
        return res;
    }
    int main()
    {
        int aa, bb, cc, dd;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &a[i].val);
            a[i].id = i;
        }
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &b[i].val);
            b[i].id = i;
        }
        sort(a + 1, a + n + 1, cmp);
        sort(b + 1, b + n + 1, cmp);
        for (int i = 1; i <= n; i++)
            q[a[i].id] = b[i].id;
        long long answer = 0;
        for (int i = 1; i <= n; i++)
        {
            update(q[i], 1);
            answer += i - getsum(q[i]);//用来存储原数第i个数的order下标是什么
        }
        printf("%lld
    ", answer%(99999997));
    }

    参考:https://blog.csdn.net/m0_38033475/article/details/80330157

  • 相关阅读:
    51 Nod 1086 多重背包问题(单调队列优化)
    51 Nod 1086 多重背包问题(二进制优化)
    51 Nod 1085 01背包问题
    poj 2559 Largest Rectangle(单调栈)
    51 Nod 1089 最长回文子串(Manacher算法)
    51 Nod N的阶乘的长度 (斯特林近似)
    51 Nod 1134 最长递增子序列(经典问题回顾)
    51 Nod 1020 逆序排列
    PCA-主成分分析(Principal components analysis)
    Python中cPickle
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/12828425.html
Copyright © 2011-2022 走看看