·哦,这题要用优先队列?那大米饼就扔一个手写堆上去吧!

·英文题,述大意:

      输入n个长度为n的序列(题中是k,2<=k<=750)。一种结果定义为:从每个序列中都要挑选一个数加起来。挑选的不同种结果含有的元素可以重复,现在你需要求出在所有的nn个结果中,找到其中最小的n个结果,然后按照从小到大顺序输出这n个结果。

·分析:

     我们可以从简单情况加以考虑以得到普遍结论。

     当只有1个序列时,那么就直接排个序就可以了(虽然不在数据范围里)。

     当只有两个序列,也就是挑选出两个数(来自不同序列)的和我们要的结果。首先,我们怎么取得最小的那个和?毫无疑问,就是这个序列两个的最小数的和。那么第二小的数怎么取得?嗯嗯,肯定是这样:

 第二小数=Min(1序列最小数+2序列第二小数,1序列第二小数+2序列最小数)

这样一直思考下去,现在我们知道了第i小的结果,要的到第(i+1)小的结果,就有两种选择加以比较。为了便于我们找到单个序列中第i大,我们给所有序列从小到大排序。

      排序后,我们可以知道一个这样的结论:假设现在选择的第p大的组合是a[i]+b[j](注意,排好序了的),那么第p大肯定不会去考虑a[i]+b[j+1],因为a[i]+b[j]<a[i]+b[j+1]。这句奇怪的话只是想说明一个问题,在a[i]+b[j]都还没有被选为答案时,a[k]+b[t](k>=i,t>=j,且等号不同时成立)肯定不用管(管的意思是拿去进行Min的比较)。

      快速维护大小关系,我们可以使用优先队列,将各式各样的组合塞进去。但是我们把所有的压进去,时间耗费太多(n*n啊!)。所以,使用上文的结论,那么上文在CODE中的意义是,a[i]+b[j]在优先队列中时,a[k]+b[t]无需存在。当我们挑选第k大的结果时,就是队首元素啦。那么接下来怎么维护?我们是用有序表:(注意a,b还是排好序了的)

               a1+b1<=a1+b2<=a1+b3……<=a1+bn

                a2+b1<=a2+b2<=a2+b3……<=a2+bn

     这样做的话,我们维护了a的有序,那么对于每个组合,当a[i]+b[j]出队被选为答案后,我们就立刻将a[i]+b[j+1](前提是j+1<=n)加入队列作为将来可能的答案。到此我们可以推而广之,有n个序列时,我们输入一个b就和合并一次,将最小的答案直接塞到a中,操作n-1次合并,就完事啦。

     手写了一个小堆堆,但是这道题数据小,手写堆没发挥优势。

     代码来了:

 #include<stdio.h>
#include<algorithm>
#define Exchange(a,b) a^=b^=a^=b
#define go(i,a,b) for(int i=a;i<=b;i++)
using namespace std;const int N=;
int n,a[N],b[N],val[N],I[N];
struct Heap
{
int sz,cur[N],fa,v;
inline void Up_Adjust(int u)
{
fa=u>>;while(u!=&&val[cur[fa]]>val[cur[u]])
Exchange(cur[fa],cur[u]),fa=(u=fa)>>;
}
inline void Down_Adjust(int u)
{
v=u<<;while(v<=sz){v+=val[cur[v]]>val[cur[v+]]&&v<sz;
if(val[cur[v]]>=val[cur[u]])return;
Exchange(cur[u],cur[v]);v=(u=v)<<;}
}
inline void Insert(int i){cur[++sz]=i,Up_Adjust(sz);}
inline void Delete(){Exchange(cur[],cur[sz]);sz--;Down_Adjust();}
}q;
int main()
{
while(~scanf("%d",&n))
{
go(i,,n)scanf("%d",&a[i]);sort(a+,a+n+);
go(k,,n)
{
go(i,,n)scanf("%d",&b[i]);sort(b+,b+n+);q.sz=;
go(i,,n)val[i]=a[i]+b[],I[i]=,q.Insert(i);
go(j,,n){int i=q.cur[];a[j]=val[i];q.Delete();
if(I[i]<n)val[i]+=-b[I[i]]+b[I[i]+],I[i]++,q.Insert(i);}
}
printf("%d",a[]);go(i,,n)printf(" %d",a[i]);puts("");
}
return ;
}//Paul_Guderian

这是一段很长很长的旅程,用尽所有的时光永无止境

我不停地奔跑呼喊和追寻,在我的路上寻找生命的意义。————汪峰《我的路》

【UVA–11997 K Smallest Sums 】的更多相关文章

  1. 【UVA 11997 K Smallest Sums】优先级队列

    来自<训练指南>优先级队列的例题. 题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18702 题意:给定 ...

  2. UVa 11997 K Smallest Sums 优先队列&amp;&amp;打有序表&amp;&amp;归并

    UVA - 11997 id=18702" target="_blank" style="color:blue; text-decoration:none&qu ...

  3. UVA 11997 K Smallest Sums 优先队列 多路合并

    vjudge 上题目链接:UVA 11997 题意很简单,就是从 k 个数组(每个数组均包含 k 个正整数)中各取出一个整数相加(所以可以得到 kk 个结果),输出前 k 小的和. 这时训练指南上的一 ...

  4. UVa 11997 K Smallest Sums - 优先队列

    题目大意 有k个长度为k的数组,从每个数组中选出1个数,再把这k个数进行求和,问在所有的这些和中,最小的前k个和. 考虑将前i个数组合并,保留前k个和.然后考虑将第(i + 1)个数组和它合并,保留前 ...

  5. 优先队列 UVA 11997 K Smallest Sums

    题目传送门 题意:训练指南P189 分析:完全参考书上的思路,k^k的表弄成有序表: 表1:A1 + B1 <= A1 + B2 <= .... A1 + Bk 表2:A2 + B1 &l ...

  6. uva 11997 K Smallest Sums 优先队列处理多路归并问题

    题意:K个数组每组K个值,每次从一组中选一个,共K^k种,问前K个小的. 思路:优先队列处理多路归并,每个状态含有K个元素.详见刘汝佳算法指南. #include<iostream> #i ...

  7. UVA 11997 K Smallest Sums (多路归并)

    从包含k个整数的k个数组中各选一个求和,在所有的和中选最小的k个值. 思路是多路归并,对于两个长度为k的有序表按一定顺序选两个数字组成和,(B表已经有序)会形成n个有序表 A1+B1<=A1+B ...

  8. 11997 - K Smallest Sums(优先队列)

    11997 - K Smallest Sums You’re given k arrays, each array has k integers. There are kk ways to pick ...

  9. UVA-11997 K Smallest Sums

    UVA - 11997 K Smallest Sums Time Limit: 1000MS   Memory Limit: Unknown   64bit IO Format: %lld & ...

随机推荐

  1. Tomcat 8项目无法启动,无报错

    作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs Tomcat 8启动很慢,且日志上无任何错误,在日志中查看到如下信息: Log4j:[2015-10-29 ...

  2. java8-Stream之数值流

    在Stream里元素都是对象,那么,当我们操作一个数字流的时候就不得不考虑一个问题,拆箱和装箱.虽然自动拆箱不需要我们处理,但依旧有隐含的成本在里面.Java8引入了3个原始类型特化流接口来解决这个问 ...

  3. lodash源码分析之获取数据类型

    所有的悲伤,总会留下一丝欢乐的线索,所有的遗憾,总会留下一处完美的角落,我在冰峰的深海,寻找希望的缺口,却在惊醒时,瞥见绝美的阳光! --几米 本文为读 lodash 源码的第十八篇,后续文章会更新到 ...

  4. 常用cmd代码片段及.net core打包脚本分享

    bat基础命令 注释:rem 注释~~ 输出:echo hello world 接收用户输入:%1 %2,第n个变量就用%n表示 当前脚本路径:%~dp0 当前目录路径:%cd% 设置变量:set c ...

  5. angular2 学习笔记 ( Dynamic Component 动态组件)

    更新 2018-02-07 详细讲一下 TemplateRef 和 ViewContainerRef 的插入 refer : https://segmentfault.com/a/1190000008 ...

  6. OpenID Connect + OAuth2.0

    一.问题的提出 现代应用程序或多或少都是如下这样的架构: 在这种情况下,前端.中间层和后端都需要进行验证和授权来保护资源,所以不能仅仅在业务逻辑层或者服务接口层来实现基础的安全功能.为了解决这样的问题 ...

  7. GIT入门笔记(16)- 分支创建和管理

    查看分支:git branch创建分支:git branch <name>切换分支:git checkout <name>创建+切换分支:git checkout -b < ...

  8. C# 读取网页JSON数据

    场景描述: 公司和别的系统需要对接,现在对方提供一个网址,数据都是json字符串,我需要对json数据进行处理. 提供的json数据如下格式 一.读取网址中的json数据 public string ...

  9. 【第十九篇】laydate设置起始时间,laydate设置开始时间和结束时间

    laydate设置开始时间后,结束时间不可小于已选择的开始时间 laydate设置结束时间后,开始时间不可小于已选择的结束时间 //设置开始时间 var startDate = laydate.ren ...

  10. 初学Java Web(1)——Web概述

    已经很久没有更新博客了,过年忙着吃喝玩乐,就怠惰了一小下下?幸好这学期新开的课程都比较有趣--Java Web和Android.至少对于我自己来说,既充满挑战,又富有趣味. --[1.Web概述]-- ...