倍增問題之 天才ACM

2021-09-28 18:50:38 字數 1475 閱讀 6625

下面要介紹給大家的題選自《演算法競賽高階指南》,這道題困擾了我乙個月,今天終於被我乾掉了,下面給出題目和**,希望對大家有幫助。

給定乙個整數 m,對於任意乙個整數集合 s,定義「校驗值」如下:

從集合 s 中取出 m 對數(即 2∗m 個數,不能重複使用集合中的數,如果 s 中的整數不夠 m 對,則取到不能取為止),使得「每對數的差的平方」之和最大,這個最大值就稱為集合 s 的「校驗值」。

現在給定乙個長度為 n 的數列 a 以及乙個整數 t。

我們要把 a 分成若干段,使得每一段的「校驗值」都不超過 t。

求最少需要分成幾段。

輸入格式

第一行輸入整數 k,代表有 k 組測試資料。

對於每組測試資料,第一行包含三個整數 n,m,t 。

第二行包含 n 個整數,表示數列a1,a2…an。

輸出格式

對於每組測試資料,輸出其答案,每個答案佔一行。

資料範圍

1≤k≤12,

1≤n,m≤500000,

0≤t≤1018,

0≤ai≤220

大家可以看到,這個資料量。。。出題老師真的是毒瘤之王 nb,可以想出這麼nb的題目,這種題目應該點讚給大家都做一做。

#include

#include

#include

#define ll long long

using

namespace std;

const

int n=

500010

;ll a[n]

,t1[n]

,t2[n]

;int n,m;

ll k;

bool

check

(int l,

int mid,

int r)

}int left=l,right=r,cnt=0;

ll res=0;

while

(cntleft)

if(res<=k)

return0;

}int

main()

l=r=r+1;

}printf

("%d\n"

,res);}

return0;

}

首先是倍增模板(可替代原先的二分**,但是平均效能不及二分)

int

find

(int x)

return r;

}

然後是合併兩個有序集合

void

merge

(int l,

int mid,

int r)

//[l,mid-1]和[mid,r]

}

然後把兩個核心**帶入源**看,應該就會輕鬆一點了,用倍增法不斷分割區間,最終得到答案,**非常的漂亮(不愧是李煜東大佬)

天才ACM(倍增)

題目參考題解 很好。首先考慮我們用貪心證明兩個東西 如果第 i 個可以歸到前面的部分就歸到前面的部分,不要放到後面的部分,反正放到後面也只會讓校驗值增大,還不如不放。對於乙個數列而言,如何求校驗值?答案是最大的減最小的的平方加上次大的.至於證明,首先,如果對於 x y 2 x y 而數列中有 沒有用...

AcWing 109 天才ACM 倍增

題目鏈結 這道題最基本的想法就是一次尋找每個區間,對於每個區間,用二分來判定其最大長度。每次check的時候,對區間排序,不斷取出不大於m對最大值與最小值求值即可。然後你就喜提tle了,笑如果用倍增來代替二分的話能過,不過其實倍增最壞複雜度和二分一樣,應該是資料沒有刻意來卡倍增。下面先給出倍增的 c...

AcWing 109 天才ACM 倍增 歸併

給定乙個整數 mm,對於任意乙個整數集合 ss,定義 校驗值 如下 從集合 ss 中取出 mm 對數 即 2 m2 m 個數,不能重複使用集合中的數,如果 ss 中的整數不夠 mm 對,則取到不能取為止 使得 每對數的差的平方 之和最大,這個最大值就稱為集合 ss 的 校驗值 現在給定乙個長度為 n...