Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 817 Accepted Submission(s): 296
ios
2
5 6
1 1 1 1 1
5 25
1 2 3 4 5编程
Case #1: 2
Case #2: 11ide
解题目报告测试
题目大意:spa
有N个包含难度值的题目,每次比赛能够选若干个不一样题目,则有C(N,1)+C(N,2)+...+C(N,N)种可能的题目组合的方案,每一个方案的题目难度的总和则称为比赛难度。让你输出第M小的方案的比赛难度。code
思路:blog
若是只是考虑去计算因此方案的比赛方案的话,0<N<=10000,方案数有C(N,1)+C(N,2)+...+C(N,N),不可能枚举因此的方案数再去求第M小的方案的比赛难度。队列
不过,M的范围是限制在(0,10000]之间,也就是这题的突破口在在于直接求解第M小的数便可,也就是每次取出最小的那个方案的比赛难度,取M次便可、ip
假如咱们有N个题目,题目难度分别为X1,X2,X3...XN(Xi<=XJ,i<j)。string
咱们能够很容易知道,比赛方案最小的比赛难度为X1,
一样,也能够知道,比赛方案第二小的比赛难度为X2,
若是继续求解第三小的比赛难度,那第三小的是X1+X2,仍是X3呢,
若是,第三小的是X3,那么第四小的是X1+X2,仍是X4呢。
若是,第三小的是X1+X2,那么第四小的是X1+X3,仍是X3呢?
对于求最小值或者最大值的问题,咱们能够用优先队列来求解,但如何求解也在于你如何构造一个合理的结构体来实现、
首先,咱们要构造的这个结构体,确定是要来记录某一个方案的比赛难度的总和、
而后,咱们能够肯定的是第一小的方案的比赛难度,可是如何实现记录每个方案的比赛难度呢?
咱们先把全部题目的比赛的难度都先排好序,从小到大依次拿题目,便能保证你下一个方案的比赛难度是递增的。
咱们保证,第一次拿出来的结构体(方案)是最小的,而后在第一次那结构体(方案)的基础上,放入比它大的其余方案(结构体),这样,每次一样的操做,即可以实如今第M次拿出第M小的方案的比赛难度。
咱们要实现每一个方案先后是有关联的,也就是说咱们须要构建的结构体也是须要可以关联到先后方案的。
咱们在结构体里面,定义一个Sum,用来记录以前方案的比赛难度的总和。(前关联)
而后在定义一个ID,则是表示当前加入的方案的题目难度。(后关联)
每个结构体表示的方案的比赛难度则是=Sum+Num[ID];
1 struct Node 2 { //每个结构体表示一种题目难度总和=Sum+Num[ID]; 3 int Sum;//记录以前题目难度的总和, 4 int ID;//记录下一个题目的难度 5 friend bool operator <(Node a,Node b){ 6 return a.Sum+Num[a.ID]>b.Sum+Num[b.ID]; 7 }//把题目难度总和比较小的优先 8 };
构建完结构体,还有很重要的一点是,如何正确放入下一个方案?
咱们能够知道,对于当前方案的话,比赛的难度为Sum+Num[ID],那么,比他大的方案有也就只有Sum+Num[ID+1]。(更新下标值)
并且,你还须要更新下一个方案的比赛难度的总和,也就是(Sum+Num[ID])+Num[ID+1]。(更新方案的比赛难度总和)
用优先队列维护最小值,每次取出最小值在进行更新即可以得出第M小的方案的比赛难度、
PS:对放入(Sum+Num[ID])+Num[ID+1]仍是不太理解的话,能够想一想,虽然Sum+Num[ID+1]确定小于(Sum+Num[ID])+Num[ID+1],
但你没法肯定,你的下下一个方案也就是Sum+Num[ID+1]+Num[ID+2]是否会比(Sum+Num[ID])+Num[ID+1]小?
这样, 也才可以把全部方案从小到大都放入优先队列中,在不懂的就本身去画画图就大概知道为何了、
1 #include <iostream> 2 #include <algorithm> 3 #include <string> 4 #include <queue> 5 #include <stdio.h> 6 #include <string.h> 7 #include <stdlib.h> 8 using namespace std; 9 int Num[10100];//Num[i],记录第i个题目的难度 10 struct Node 11 { //每个结构体表示一种题目难度总和=Sum+Num[ID]; 12 int Sum;//记录以前题目难度的总和, 13 int ID;//记录下一个题目的难度 14 friend bool operator <(Node a,Node b){ 15 return a.Sum+Num[a.ID]>b.Sum+Num[b.ID]; 16 }//把题目难度总和比较小的优先 17 }; 18 int main() 19 { 20 int T,N,M,i,t=1; 21 Node TMD; 22 scanf("%d",&T); 23 while(T--){ 24 priority_queue<Node>q; 25 scanf("%d%d",&N,&M); 26 for(i=0;i<N;i++){ 27 scanf("%d",&Num[i]); 28 } 29 sort(Num,Num+N);//将题目难度小的排在前面 30 TMD.Sum=0;//初始状态,题目难度为0 31 TMD.ID=0;//默认从最小的开始 32 q.push(TMD); 33 printf("Case #%d: ",t++); 34 while(M--){ 35 TMD=q.top();q.pop(); 36 if(M==0){//输出第M小的题目难度总和 37 printf("%d\n",TMD.Sum+Num[TMD.ID]); 38 } 39 if(++TMD.ID<N){ 40 q.push(TMD);//更新的下标值的 41 TMD.Sum+=Num[TMD.ID-1]; 42 q.push(TMD);//更新下标值以及总和 43 } 44 } 45 } 46 return 0; 47 }