【CodeVS】1245 最小的N个和 - Ⅰ - 原题的几种解法
来源:互联网 发布:火影忍者手游开挂软件 编辑:程序博客网 时间:2024/05/07 12:22
【题意】有两个长度为
【数据范围】
【思路1】30分做法
直接把
时间复杂度:
空间复杂度:
【思路2】AC做法
求前N小,涉及到单调性,试着排序使得A,B两个序列从小到大。
我们从1到N依次找到前N小的和,那么每次就要从决策中选出一个最小的元素,现在要求每次决策考虑的元素个数尽可能少。
可以按行把所有的
第1行:
第2行:
第i行:
第n行:
对于第i行,若
那么,在决策的时候只用考虑每一行当前未选的最前一个。
即:设l
至于每次的决策,用堆可以做到
时间复杂度:
空间复杂度:
代码:实测136ms
#include <cstdio>#include <cctype>#include <queue>#include <algorithm>using namespace std;const int N=161240;int n;int A[N],B[N];int lev[N];inline int Read(void){ int s=0,f=1; char c=getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; for (;isdigit(c);c=getchar()) s=s*10+c-'0'; return s; }struct cmp{ inline int operator () (int i,int j) { return A[i]+B[lev[i]]>A[j]+B[lev[j]]; }};priority_queue<int,vector<int>,cmp> q;int main(void){ n=Read(); for (int i=1;i<=n;i++) A[i]=Read(); for (int i=1;i<=n;i++) B[i]=Read(); sort(A+1,A+n+1); sort(B+1,B+n+1); fill(lev+1,lev+n+1,1); for (int i=1;i<=n;i++) q.push(i); int now; for (int i=1;i<=n;i++) { now=q.top(),q.pop(); printf("%d ",A[now]+B[lev[now]++]); q.push(now); } printf("\n"); return 0;}
【思路3】AC做法
首先排序,然后还是用【思路2】的思路,从1到N依次求前N小。
注意到【思路2】中我们只使用了横向的分类,而没有考虑纵向的分类,这是可以有一些决策状态排除掉的。
于是我们想到直接把这些状态当作一个二维的图来看:
其中
我们变为了二维的扩展,即在当前状态中选择一个最小的,然后向下、向右扩展决策状态。
这里需要注意的是,有些格子是不用加入待决策状态中的:它的左边或上边还没有决策出来。
这样有一定的优化作用。
时间复杂度:
空间复杂度:
代码:实测88ms
#include <cstdio>#include <cctype>#include <queue>#include <algorithm>using namespace std;#define mp(i,j) make_pair(i,j)#define fs first#define sc secondtypedef pair<int,int> PairInt;const int N=161240;int n;int A[N],B[N];int cross[N],line[N];inline int Read(void){ int s=0,f=1; char c=getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; for (;isdigit(c);c=getchar()) s=s*10+c-'0'; return s; }struct cmp{ inline int operator () (PairInt Pi,PairInt Pj) { return A[Pi.fs]+B[Pi.sc]>A[Pj.fs]+B[Pj.sc]; }};priority_queue<PairInt,vector<PairInt>,cmp> q;inline int Check(int i,int j){ if (cross[i]+1<j) return 0; if (line[j]+1<i) return 0; return 1;}int main(void){ n=Read(); for (int i=1;i<=n;i++) A[i]=Read(); for (int i=1;i<=n;i++) B[i]=Read(); sort(A+1,A+n+1); sort(B+1,B+n+1); PairInt now; q.push(mp(1,1)); for (int i=1;i<=n;i++) { now=q.top(),q.pop(); printf("%d ",A[now.fs]+B[now.sc]); cross[now.fs]=now.sc; line[now.sc]=now.fs; if (Check(now.fs+1,now.sc)) q.push(mp(now.fs+1,now.sc)); if (Check(now.fs,now.sc+1)) q.push(mp(now.fs,now.sc+1)); } printf("\n"); return 0;}
【思路4】AC做法
按照【思路1】,我们把所有可能的情况都算出来,然后排序。
然而【思路1】的时间和空间都是我们承受不了的,怎么办?
想办法把一些一定不可能的状态给消除掉。
首先还是给A,B排序,同样还是这个表:
观察到,对于
由于我们要求前N小的,所以满足要求的点至少要满足
这样我们可以把点的个数缩小至
时间复杂度:
空间复杂度:
代码:实测172ms
#include <cstdio>#include <cctype>#include <algorithm>using namespace std;const int N=161240;const int S=3000000;int n;int A[N],B[N];int t[S],len;inline int Read(void){ int s=0,f=1; char c=getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; for (;isdigit(c);c=getchar()) s=s*10+c-'0'; return s; }int main(void){ n=Read(); for (int i=1;i<=n;i++) A[i]=Read(); for (int i=1;i<=n;i++) B[i]=Read(); sort(A+1,A+n+1); sort(B+1,B+n+1); for (int i=1;i<=n;i++) for (int j=1;i*j<=n;j++) t[++len]=A[i]+B[j]; sort(t+1,t+len+1); for (int i=1;i<=n;i++) printf("%d ",t[i]); printf("\n"); return 0;}
【小结】
对于无序的集合,通常要将它定序,常见的定序方法就是从小到大或者从大到小。
求第K小的方法通常有以下几种:
①依次求
②排序可能情况
③二分答案对于方法①“依次求”,每次在待定状态内的元素要尽可能少,可以通过某些性质来减少元素的个数。
通常的做法是构建多条元素的单调序列,满足先选完前一个再选后一个,这样用优先队列甚至不用(例如《丑数》一题)即可。
这种做法甚至可以扩展到二维单调性,然后在平面上扩展。对于方法②“排序可能情况”,待定情况要尽可能的少,这要通过某些性质来排除一些不可能的情况。
例如本题只限定在i×j≤n 内求,最后弄出了调和级数,总共的情况数为O(nlogn) 。对于方法③,在【变式】会提及。
方法的比较
方法①,方法②处理范围较小,询问较多的问题;
方法③处理范围较大,询问较少的问题。
- 【CodeVS】1245 最小的N个和 - Ⅰ - 原题的几种解法
- [codevs 1245] 最小的N个和
- CODEVS 1245最小的N个和
- CODEVS 1245 最小的N个和
- Codevs 1245 最小的N个和
- codevs 1245 最小的N个和
- CODEVS 1245 最小的N个和 堆+排序
- 【CodeVS】1245 最小的N个和 - Ⅱ - 变式Ⅰ
- n个数 找到最小的k个数 几种解法 和java实现
- 二叉堆以及排序(codevs 1245 最小的N个和)
- wikioi 1245 最小的N个和
- 1245 最小的N个和
- 最小的N个和
- wikioi p1245 最小的N个和
- wiki1245-最小的N个和
- codevs1245 最小的N个和
- m的n次幂的几种解法
- Wiki OI 1245 最小的N个和
- 读apache代码v2.0---发文于2015-5-6
- 闭包
- s3c2440 LCD驱动
- android 电池电量上报管理
- direct UI总结---发文于2013.11.17
- 【CodeVS】1245 最小的N个和 - Ⅰ - 原题的几种解法
- IBM 服务器系统安装,以windows server 2008 为例
- 音素、音节
- 检测数组成员
- fitsSystemWindow作用
- [乡土民间故事_徐苟三传奇]第十三回_街上人都叫苟三爹
- 欢迎使用CSDN-markdown编辑器
- [乡土民间故事_徐苟三传奇]第十四回_捉鲫鱼误时遭棒打
- 读modsecurity代码 ---发文于2015-5-6