小明的账单

题目描述

小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单… 在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没有支付的账单会被保留到下一天。 请你帮他计算出支付的顺序。

输入

第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看来不能直接排序了。

  1. 很容易发现,以这种方法,以前的数据是有序的,只有今天的数据是无序的。可以用归并的思想,把今天的弄成有序的(sort方便),然后合为一条有序的数列。              但还是超时
  2. 如果数据多的话中间有一串是没用的,既不是太大也不是太小。到最后一天也还不了,但每天都要排序的。这种数据就可以直接删去。具体是如果今天是第 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值