A - 比赛难度 HDU - 4546
最近,小明出了一些ACM编程题,决定在HDOJ举行一场公开赛。
假设题目的数量一共是n道,这些题目的难度被评级为一个不超过1000的非负整数,并且一场比赛至少需要一个题,而这场比赛的难度,就是所有题目的难度之和,同时,我们认为一场比赛与本场题目的顺序无关,而且题目也不会重复。
显而易见,很容易得到如下信息:
假设比赛只用1个题目,有n种方案;
假设比赛使用2个题目,有(n-1)n/2种方案;
假设比赛使用3个题目,有(n-2)(n-1)*n/6种方案;
…
假设比赛使用全部的n个题目,此时方案只有1种。
经过简单估算,小明发现总方案数几乎是一个天文数字!
为了简化问题,现在小明只想知道在所有的方案里面第m小的方案,它的比赛难度是多少呢?
Input
输入数据的第一行为一个整数T(1 <= T <= 20),表示有T组测试数据。
每组测试数据第一行为两个整数n, m(0 < n, m <= 10000),表示现在有n个题目,现在要求第m小的方案的比赛难度。接下来第二行有n个数字,分别表示这n个题目的难度值。
Output
对于每组测试数据,输出一行"Case #c: ans"(不包含引号),ans 表示要求的第m小的比赛难度,输入数据保证存在第m小的方案,具体参见样例。
Sample Input
2
5 6
1 1 1 1 1
5 25
1 2 3 4 5
Sample Output
Case #1: 2
Case #2: 11
- 题解:看完别人的题解才能白怎么做.首先要把所有的题目难度排下序,然后根据题意找到第m小的数,要一个一个从小到大去找,主要难点就是准确从第i个到第i+1个.这里用到了优先队列,根据情况,要恰好变成下一个的话,有两种情况,第一中就是目前这个已经包含的题目均比要加的题目[i+1]所占的难度大,那么就直接加上[i+1]的难度;另一种是已经包含的题目有比这个题目难度小的,那么加上这个题目难度后再减去那些已经包含题目中的最大难度的那个.这里用到了优先队列去维护,这个范围.因此node 结构体维护了两个信息,第一个就是当下的所有题目的和,第二个就是当下所选题目最后的那个题目位置
#include<bits/stdc++.h>
#define mk make_pair
#define endl '\n'
#define pb pusk_back
#define _ ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
const double EPS = 1e-10;
const double PI = acos(-1);
bool SUBMIT = 1;
const int inf = 10100;
const int INF = 1e9;
int n,m,sum;
int sn[inf];
struct node{
int x,y;
bool operator<(node b)const{
return x>b.x;
}
};
int fun(){
priority_queue<node>q;//node 的x值代表当下题目难度和
node t;int pos=0;//pos 代表当下所加的值最后面的sn指针
sum=0;sn[n]=INF;
t.x=sn[0],t.y=0;q.push(t);
for(int i=1;i<=m;i++){
t=q.top();q.pop();
sum=t.x;pos=t.y;
t.x=sum+sn[pos+1];
t.y++;
q.push(t);
t.x=sum+sn[pos+1]-sn[pos];
q.push(t);
}
return sum;
}
int main()
{
if(!SUBMIT)freopen("i.txt","r",stdin);else _;
int t;cin>>t;
for(int i=1;i<=t;i++){
cin>>n>>m;
for(int i=0;i<n;i++)cin>>sn[i];
sort(sn,sn+n);
cout<<"Case #"<<i<<": "<<fun()<<endl;
}
return 0;
}