题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;
}