• 树状数组 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

  • 相关阅读:
    获取代理服务器ip列表的方法
    司机奖励新政策:失去的奖励还能再回来!
    成都Uber优步司机奖励政策(2月24日)
    北京Uber优步司机奖励政策(2月24日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(2月24日)
    成都Uber优步司机奖励政策(2月23日)
    北京Uber优步司机奖励政策(2月23日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(2月23日)
    Android Studio 模拟器启动问题——黑屏 死机 解决方法
    MYSQL使用mysqldump导出某个表的部分数据
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/12828425.html
Copyright © 2020-2023  润新知