题解 P1631 【序列合并】

雷州半岛岛主

2018-04-01 13:57:12

Solution

~~**各位,我发现有一种新奇的做法就能解决此题~**~~ # 39行实测AC代码+思路 ## 先讲思路。 - 很显然我们有 _a和b两个数组_ 。 - 很显然我们要用一个 _c数组存和_ 。 - 很显然要用heap堆排(**实际上是只用了向下维护操作**)。 - 我们的c[ i ][ j ],用来存储**a中第i个数分别和b中的所有数相加得到的结果**。很显然 会 爆空间,所以等下会有优化。 ```cpp for (int i = 1;i <= n;i++) for (int j = 1;j <= n;j++) c[i][j] = a[i]+b[j];//a中第i个数分别和b中的所有数相加得到的结果 ``` - 依题意得:a是有序数列,b也是有序数列,则对于任意c[ i ]也会是一个有序数列。 - 那么我们就把c[ i ]的第一个数存入heap。 ```cpp for (int i = 1;i <= n;i++) heap[i] = c[i][j]; ``` - 然后维护一下heap - while(没有输出够n个数) - { - 输出; - 放入 **堆顶数所在的数组的下一个数**(好好咀嚼一下) - 维护 - } ### 优化 - 经过arfa同志的提醒,我们发现定义的c数组会爆空间。 - 于是我们开始了优化之旅。 - 首先我们知道,heap[ i ]只需要用一个值,那我们可不可以在heap需要的时候再把c[ i ][ j ]算出来呢? - 然后我们发现 c[ i ][ j ] = a[ i ]+b[ j ]中i相当于目前对顶数所在的数组,j就表示下一个数的下标。 - 于是优化就出来了。 ```cpp for (int i = 1;i <= n;i++) heap[i] = a[i]+b[1] …… int t = from[1]; step[t]++; heap[1]=a[t] + b[ step[t] ]; ``` - 有人可能看不懂。我做一个比喻吧。假如你是拱野驾校隔壁的老王肠粉店店长,因为拱野驾校的学员很多,所以你的生意很红火。但是他们想要各种口味的。你想了一个办法:买来几个碟子,先把各种肠粉都做几份,再卖出去。实际上,你只需要现做现卖的合成就~~ojbk~~了。 ## 上代码 ```cpp #include<bits/stdc++.h> using namespace std; int a[100000],b[100000],heap[100000],from[100000],step[100000],n,sum=1; void swap(int x,int y)//手打swap交换,同时交换来源数组。 { int k = heap[x]; heap[x] = heap[y]; heap[y] = k; k = from[x]; from[x] = from[y]; from[y] = k; } int main() { scanf("%d",&n); for (int i = 1;i <= n;i++) scanf("%d",&a[i]); for (int i = 1;i <= n;i++) scanf("%d",&b[i]); for (int i = 1;i <= n;i++) heap[i] = a[i]+b[1],from[i] = i,step[i] = 1; //这一步就是优化。把c去掉了,取而代之的是现做现卖的合成。 while (sum <= n) { printf("%d ",heap[1]); int t = from[1]; step[t]++; heap[1]=a[t] + b[ step[t] ];//现做现卖的合成。 int x = 1,s; while (x<<1 <= n)//经典的下传 { s = x<<1; if (heap[s] > heap[s + 1] && s + 1 <= n) s++; if (heap[x] > heap[s]) { swap(x,s); x = s; }else break; } sum++; } return 0; } ```