G2-11 wls要吃饭 (25 分)
群友们经常喊wls吃饭,但是wls很忙经常忘记。又因为他没有女朋友,也没有练成一个人去商场吃饭的本领。
所以他就买了很多面包。每个面包都有能量。 每天wls早上都会买一个面包,但是他不一定记得吃。
需要群友提醒,群友只会在晚上提醒,每次提醒的时候,wls都会从他当前所有面包里面挑出一个,然后吃掉。但这是他想起了AA姐说的要减肥。所以只挑最小的。
(如果没有面包了,wls没有办法,只能饿肚子了)
输入格式:
第一行两个数n,m(m<=n) 下一行n个数a1,a2,a3......an. ai表示第i天wls买的面包包含的能量。
再下一行m个数字b1,b2.....bn表示第i个群友在bi天提醒wls吃饭
1<=ai,<=1001<=bi<=n,<=1e5
输出格式:
输出wls总共获得了多少能量
输入样例:
在这里给出一组输入。例如:
5 2
5 4 3 2 1
3 4
输出样例:
在这里给出相应的输出。例如:
5
时间限制 1000 ms
代码如下:
主要是需要一个可以储存可重复数字并排序的容器 (排序时间复杂度为logn)
若排序方法时间复杂度高则容易超时
优先队列priority_queue:
#include<bits/stdc++.h>
using namespace std;
int n , m , last=1;
int bread[100005] , qy[100005];
long long power;
priority_queue<int ,vector<int>,greater<int> > que;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>bread[i];
for(int i=1;i<=m;i++)
cin>>qy[i];
for(int i=1;i<=m;i++)//对于每次朋友提醒,找已买面包的最小值
{
for(int j=last;j<=qy[i];j++)/从上一次被提醒之后的1天买的面包,到这次被提醒这天买的面包,把面包加入到priority_queue中
{
{
que.push(bread[j]);//priority_queue可以保持排序,并保证每次插入的时间是logN
}
if(!que.empty()) //没有面包则不用处理
{
power+=que.top();//获得优先队列的第一个元素就是最小元素了,即最小的面包
que.pop();//把已吃的面包的从priority_queue里面去掉
}
last=qy[i]+1;//为下一轮循环作准备
}
cout<<power<<endl;
return 0;
}
multiset:以下为老师给的代码
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
int main()
{
int n,m,i,j,k,mina,next=1,last,sum=0;
int a[100005];
int b[100005];
//multiset可以保持排序,且支持重复元素,并且保证每次插入的时间是logN。或者用map来处理也可以
multiset<int> s;
cin>>n>>m;
for(i=1;i<=n;i++)
{
cin>>a[i];
}
for(j=1;j<=m;j++)
{
cin>>b[j];
}
//sort(b+1,b+1+m); //题目貌似b[i]本身就是从小到大的,不用排序。
for(j=1;j<=m;j++) //对于每次朋友提醒,找已买面包的最小值
{
last=b[j];
for(k=next;k<=last;k++) //从上一次被提醒之后的1天买的面包,到这次被提醒这天买的面包,把面包加入到multiset中
{
s.insert(a[k]); //multiset可以保持排序,并保证每次插入的时间是logN
}
if(!s.empty()) //如果还有面包
{
mina = *s.begin(); //获得multiset的第一个元素就是最小元素了,即最小的面包
s.erase(s.begin()); //把已吃的面包的从multiset里面去掉(注意要删除指定位置的元素,而不能用s.erase(mina)这样如果有重复会都删掉)
}
else //如果已没有面包
{
mina=0;
}
sum += mina; //累加
next=k; //为下一轮循环作准备
}
cout<<sum<<endl;
return 0;
}