P1631序列合併

2022-06-04 10:45:08 字數 1179 閱讀 7696

題意:​ 有兩個長度都為n(1<=n<=100000)的序列a和b,在a和b中各取乙個數相加可以得到n2個和,求這n2個和中最小的n個。

思路:​ 首先會想到暴力,o(n^2),一看範圍十萬,肯定受不了。

​ 再考慮貪心,以兩個佇列的頭相加,進入前n小的和中,然後選擇兩頭中較大的元素彈出,以此類推,但我發現乙個問題:雖然這樣所找出的元素滿足單調遞增,但每個被彈出的元素在彈出後就不用了,將會導致的情況我用乙個樣例來表示:

5

2 4 9 10 11

1 1 1 1 1

答案顯然是3 3 3 3 3,然而貪心給出的是3 5 10 11 11。

​ 考慮記憶化搜尋和dp,但記憶化的f存什麼呢?存第n個最小的和嗎?但我們還不知道第n小的和的值,存當前已知的數值嗎?顯然不行。dp似乎行得通,dp通常用於最優性問題,但我沒想出來。

​ 我發現題目中有:ai<=a,bi<=b。那麼可以得出:

\[a_i+b_i\le a_+b_i,a_i+b_

\]​ 所以每得到乙個和n=ai+bi,那麼就將ai+1和bi的和與ai和bi+1的和放入某個容器,而這個容器中的最小者定為下乙個最小的(想想為什麼?)。

​ 那麼既然是堆的題,又是求最小者,那麼這個容器的最佳候選者應當是小根堆,堆的插入、刪除操作都只有o(log2(n))的複雜度,要找n個最小和,就是o(nlog2(n))的複雜度,可以承受。

100分ac**#include using namespace std;

int n,cnt=0;

int a[100005];

int b[100005];

struct nodeheap[200005];

void upd(int now)

if(heap[j].num>1;

if(heap[f].num>heap[now].num)

return ;

}int main() {

cin>>n;

for(int i=1;i<=n;i++)cin>>a[i];

for(int i=1;i<=n;i++)cin>>b[i];

heap[++cnt].num=a[1]+b[1];

heap[cnt].a=1;

heap[cnt].b=1;

for(int t=1;t<=n;t++){

cout《大功告成!

P1631 序列合併

做法 將 a 和 b 都從小到大排一遍序。然後組成這樣乙個矩陣 a1 b1 a1 b2 a1 b3 a1 bn a2 b1 a2 b2 a2 b3 a2 bn a3 b1 an b1 an b2 an b3 an bn 正確性 我們先把每行的頭扔進堆裡,每行的頭是每行中的最小值,所以這樣我們能在堆裡...

P1631 序列合併

有兩個長度都是n的序列a和b,在a和b中各取乙個數相加可以得到n 2個和,求這n 2個和中最小的n個。輸入格式 第一行乙個正整數n 第二行n個整數ai,滿足ai ai 1且ai 10 9 第三行n個整數bi,滿足bi bi 1且bi 10 9.資料規模 對於50 的資料中,滿足1 n 1000 對於...

P1631 序列合併

有兩個長度都是n的序列a和b,在a和b中各取乙個數相加可以得到 n 2n2 個和,求這 n 2n2 個和中最小的n個。輸入格式 第一行乙個正整數n 第二行n個整數 a iai 滿足 a i le a ai ai 1 且 a i le 10 9ai 10 9 第三行n個整數 b ibi 滿足 b i ...