P1631 序列合并(贪心)

P1631 序列合并(贪心)

传送门

思路:要求前 n n n个最小的数,显然不能全部枚举 n 2 n^2 n2个出来,考虑如何去除不可能的情况,显然当对于 a [ i ] + b [ j ] a[i]+b[j] a[i]+b[j]显然当 ( i − 1 ) × ( j − 1 ) ≥ n (i-1)\times(j-1)\geq n (i1)×(j1)n显然不用再继续下去了,因为根据数组的单调性可知前面 ( i − 1 ) × ( j − 1 ) (i-1)\times(j-1) (i1)×(j1)个数显然都小于等于 a [ i ] + b [ j ] a[i]+b[j] a[i]+b[j]

时间复杂度: O ( n ( l o g n ) 2 ) O(n(logn)^2) O(n(logn)2)

证明:对于 1 1 1最多有 n n n个,对于 2 2 2最多 n 2 \dfrac{n}{2} 2n个,以此类推

( 1 + 1 2 + … 1 n ) ≈ l n ( n ) (1+\dfrac{1}{2}+\dots\dfrac{1}{n})\approx ln(n) (1+21+n1)ln(n)

再乘上上从小到大排序的 l o g n logn logn 所以就是 O ( n ( l o g n ) 2 ) O(n(logn)^2) O(n(logn)2)

#include
#include 
#include
typedef long long ll;
#define re register//寄存类型变量,加快读取速度
using namespace std;
const int N=1e5+5;
inline void read(int &x){ 
	x=0;
	char ch;
	for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar())
		x=(x<<3)+(x<<1)+(ch&15); 
}
int n,a[N],b[N];
int main(){
	read(n);
	for(re int i=1;i<=n;i++) read(a[i]);
	for(re int i=1;i<=n;i++) read(b[i]);
	priority_queue<int>q;
	for(re int i=1;i<=n;i++)
		for(re int j=1;(i-1)*(j-1)<=n&&j<=n;j++)
			q.push(-a[i]-b[j]);//大根堆转小根堆 
		for(int i=0;i<n;i++){
			printf("%d ",-q.top());
			q.pop();
		}
	return 0; 
}


你可能感兴趣的:(贪心)