zoukankan      html  css  js  c++  java
  • CDQ分治-------luoguP2345 [USACO04OPEN]MooFest G题解

    题目链接:(https://www.luogu.com.cn/problem/P2345)

    这道题大多数人的解法是根据v来进行排序,而我则是用的排序x的方法,看见还没人发就来发一篇.(这道题数据真滴水啊)

    解题步骤

    首先我们可以看到,题目中给的是许多奶牛的坐标和听力值,我们很容易联想到把其中中一个元素进行排序,这样子就可以只用考虑其中的一个元素了 然而我解这道题的时候联系到了三值偏序问题,(将a作为第一关键字排序后再用归并排须排序b值的时候无论怎么变换,在范围[l,mid]里面的a值都会小于范围[mid+1,r]中的a值,然后就是骚操作来了),所以我就排序了奶牛的坐标

    接着我又利用归并排须,排序v的同时计算出答案

    具体解题细节

    首先:一定要记得开longlong

    答案的计算公式

    解释一下:大家应该都知道归并排序的原理,就是两个序列进行合并。而在此算法中第一个序列的“x”数值一定小于任意一个第二个序列的“x”数值

    rt记录的就是目前已经被合并的第二序列的数的“x”数值之和

    lt记录的就是目前已经被合并的第一序列的数的“x”数值之和

    t1表示的就是目前到了序列一的第几个位置了,t1-l就是当前节点减去起点就是已经合并的序列1的数的个数

    然后t2表示的就是目前到了序列2的第几个位置了,t2-mid-1就是当前节点减去起点就是已经合并的序列2的数的个数

    1.res+=T[t1].v*(rt-(t2-mid-1)*T[t1].x),t1++;//如果当前节点是归并排序中属于序列1合并来的,那么它的x一定比已经合并的属于序列2的数的x值小,
    
    //                                          对于任意的序列1中的“x”数值一定小于序列二中的数值,所以任意序列2中的“x”数值减去序列1中的 “x”数值一定大于0,
    
    //                                          同时又因为序列2中的每一个数都要减去当前这个合并进去的数的“x”数值,
    
    //                                      所以直接用目前已经被合并的第二序列的数的“x”数值之和减去已经合并的序列2的数的个数与当前点的“x”数值的乘积就行了
    
    2.res+=T[t2].v*((t1-l)*T[t2].x-lt),t2++;//如果是当前节点在归并排序中属于序列2合并来的,那么它的x一定比前面的大,上面解释的很详细,不赘述了。

     

    (还有就是我在此处通过一点点的推断可以去除绝对值,具体见答案计算以及上面提到的“在范围[l,mid]里面的a值都会小于范围[mid+1,r]中的a值”)

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long 
    struct node{int v,x;}T[20005],b[20005];
    int n,res=0;
    int cmp(node A,node B){
        if(A.x != B.x)return A.x<B.x;
        return A.v<B.v;
    }
    int CDQ(int l , int r){
        if(l == r)return 0;
        int mid=(l+r)>>1;
        CDQ(l,mid);CDQ(mid+1,r);
        int t1=l,t2=mid+1,lt=0,rt=0;
        for (int i = l ; i <= r ; i ++){
            if(T[t1].v <= T[t2].v && t1 <= mid || t2 > r )
            b[i]=T[t1],lt+=T[t1].x,//合并序列的同时计算答案
            res+=T[t1].v*(rt-(t2-mid-1)*T[t1].x),t1++;
            else b[i]=T[t2],rt+=T[t2].x,
            res+=T[t2].v*((t1-l)*T[t2].x-lt),t2++;;
        }
        for (int i = l ; i <= r ; i ++)T[i]=b[i];
        return 0;
    }
    signed main(){
        cin>>n;
        for (int i = 1 ; i <= n ; i ++)
        cin>>T[i].v>>T[i].x;
        sort(T+1,T+1+n,cmp);
        CDQ(1,n);
        cout<<res;
        return 0;
    }
     
  • 相关阅读:
    n个元素进栈,有几种出栈方式
    The following IP can be used to access Google website
    一个未排序整数数组,有正负数,重新排列使负数排在正数前面,并且要求不改变原来的 相对顺序 比如: input: 1,7,-5,9,-12,15 ans: -5,-12,1,7,9,15 要求时间复杂度O(N),空间O(1) 。
    当今世界最受人们重视的十大经典算法
    指针
    变量作用域和生存期
    一篇文章搞清spark内存管理
    Spark的Shuffle是怎么回事
    一篇文章搞清spark任务如何执行
    scala这写的都是啥?一篇文章搞清柯里化
  • 原文地址:https://www.cnblogs.com/MYCui/p/13535251.html
Copyright © 2011-2022 走看看