1. 程式人生 > 實用技巧 >CDQ分治題目題解-------luoguP2345 [USACO04OPEN]MooFest G題解

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;
}