莆田市C++专项选拔第一轮题4

题2:日月如梭

【题目描述】
小明同学是一个硬币收集者,收集了很多不同面值的硬币。现在他把这些硬币分成了两堆,已知两堆硬币分别有 n 和 m 枚硬币。
第一堆里有 n 枚面值为 𝑏1, 𝑏2 ,……, 𝑏𝑛 的硬币。第二堆里有 m 枚面值为 𝑐1 , 𝑐2 ,……, 𝑐𝑚 的硬币。现在小明同学想要从两堆硬币中各选择一枚硬币,使得两枚硬币的面值之和 不超过 k。请你帮助小明同学计算一下他有多少种选择方案。 不同的硬币组合,就算面值相同,也视为不同的方案。
【输入】
第一行三个整数 n, m, k,分别表示第一堆硬币的数量,第二堆硬币的数量,以及面值之和的上限。
第二行 n 个整数𝑏1, 𝑏2 ,……, 𝑏𝑛 ,表示第一堆硬币的面值。第三行 m 个整数 𝑐1 , 𝑐2 ,……, 𝑐𝑚 ,表示第二堆硬币的面值。
【输出】
输出一个整数,表示小明同学有多少种选择方案。
【输入样例1】

4 4 8
1 5 10 14
2 1 8 1

【输出样例1】

6

可选方案有: (1,2), (1,1), (1,1), (5,2), (5,1), (5,1),共 6 种。
【输入样例1】

2 3 4
4 8
1 2 3

【输出样例1】

0

【数据规模及约定】
对于30%的数据,1 ≤ n , m ≤ 1000 , 1 ≤ b , c ≤ 1000。
对于60%的数据,1 ≤ n , m ≤ 105 , 1 ≤ 𝑏𝑖, 𝑐𝑖 ≤ 1000。
对于100%的数据,1 ≤ n , m ≤ 105 , 1 ≤ 𝑏𝑖, 𝑐𝑖 ≤ 105 , 1 ≤ k ≤ 2 ×105

题目解析:

根据数据规模1 ≤ n , m ≤ 105, 1 ≤ bi , ci ≤ 105,1 ≤ k ≤ 2 ×105可确定,如果使用暴力枚举,复杂度为O(𝑛2),必定会出现超时,所以必须减少复杂度,可采用桶排序+前缀和或二分来解题。

代码如下:

//桶排序+前缀和
#include<bits/stdc++.h>
using namespace std;
const int N =2e5+5;
int b[N];
long long s[N],c[N];
int main(){
	int n,m,k,x;
	long long cnt=0;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
		cin>>b[i];	
	for(int i=1; i<=m;i++){
		cin>>x;
		c[x]++;
	}
	for(int i=1;i<=2e5;i++)
		s[i]=s[i-1]+c[i];
	for (int i=1;i<=n;i++)
		if(k>b[i])
			cnt+=s[k-b[i]];
	cout<<cnt;
	return 0;
}
//二分
#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,m,k;
	long long cnt=0;
	cin>>n>>m>>k;
	int b[n+10]={},c[m+10]={};
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=1;i<=m;i++) cin>>c[i];
	sort(b+1,b+n+1);sort(c+1,c+m+1);
	for(int i=1;i<=n;i++){	
		int l=1,r=m,mid;
		while(l<=r){
			mid=(l+r)/2;
			if(k-b[i]>=c[mid])
				l=mid+1;
			else
				r=mid-1;		
		}
			cnt+=r;
	}
	cout<<cnt;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lpstudio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值