题目描述
小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单… 在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没有支付的账单会被保留到下一天。 请你帮他计算出支付的顺序。
输入
第1行:一个正整数N(N≤15,000),表示小明补办银联卡总共的天数。
第2行到第N+1 行:每一行描述一天中收到的帐单。先是一个非负整数M≤100,表示当天收到的账单数,后跟M个正整数(都小于1,000,000,000),表示每张帐单的面额。
输入数据保证每天都可以支付两张帐单。
输出
输出共N 行,每行两个用空格分隔的整数,分别表示当天支付的面额最小和最大的支票的面额。
输入样例
4 3 3 6 5 2 8 2 3 7 1 7 0
输出样例
3 6 2 8 1 7 5 7
求最值,很容易想到的就是排序。只需要把上次剩下的和这次的合起来排序,输出第一个和最后一个就好了。看下数据N≤15,000看来不能直接排序了。
- 很容易发现,以这种方法,以前的数据是有序的,只有今天的数据是无序的。可以用归并的思想,把今天的弄成有序的(sort方便),然后合为一条有序的数列。
但还是超时 - 如果数据多的话中间有一串是没用的,既不是太大也不是太小。到最后一天也还不了,但每天都要排序的。这种数据就可以直接删去。具体是如果今天是第 i ,那么只有前 N - i + 1 和后N - i + 1天是有用的数据。其他删去即可。
完毕
#include <bits/stdc++.h>
using namespace std;
int read() //快读
{
int x;
char c;
for(c=getchar();c<'0'||c>'9';c=getchar());
for(x=0;c>='0'&&c<='9';c=getchar())
x=x*10+c-'0';
return x;
}
int bill[30105],end=0,cnt[105],ar[30105]; //前后15000加上一天100=30100,end末尾的,cnt,ar辅助
int main()
{
int n=read(),i,j,m;
for(i=1;i<=n;i++){
for(j=m=read();j>=1;j--)
cnt[j]=read();
sort(cnt+1,cnt+1+m); //排序
int bp=1,cp=1;j=1; //归并(没有归只有并)
while(bp<=end&&cp<=m)
if(bill[bp]<cnt[cp])
ar[j++]=bill[bp++];
else
ar[j++]=cnt[cp++];
while(bp<=end)
ar[j++]=bill[bp++];
while(cp<=m)
ar[j++]=cnt[cp++];
printf("%d %d\n",ar[1],ar[end+m]); //第一个和最后一个
int day=n-i; //因为今天的已经付了,所以前后n-i个有用
end+=m-2;
if(day*2>=end){ //个数少全部有用
for(j=1;j<=end;j++)
bill[j]=ar[j+1];
}else{
int cont=1;
for(j=1;j<=day;j++)
bill[cont++]=ar[j+1];
for(j=end-day+2;j<=end+1;j++) //中间删去
bill[cont++]=ar[j];
end=cont-1;
}
}
return 0;
}
某dalao五分钟打完,强大的STL中multiset自带排序,每次输出和删除就好了。
#include<bits/stdc++.h>
using namespace std;
multiset<int> st;
int main() //没啥可注释的
{
ios::sync_with_stdio(false);
int n;
cin >> n;
st.clear();
for(int i = 1;i <= n;i ++){
int m;
cin >> m;
for(int j = 1;j <= m;j ++){
int x;
cin >> x;
st.insert(x);
}
cout << *st.begin() << " ";
st.erase(st.begin());
cout << *(-- st.end()) << endl;
st.erase(-- st.end());
}
return 0;
}