CodeForces Gym 101741 A-Three Arrays(二分,规律)

题目描述

在这里插入图片描述
输入描述

在这里插入图片描述

输出描述

在这里插入图片描述
输入样例

1 3 3 3
1 2 3
1 2 3
1 2 3
1 6 6 6
1 1 2 2 3 3
2 2 3 3 4 4
3 3 4 4 5 5

输出样例

15
56

题目大意: 给定三个已排序的不同长度的数组 a,b,c,从每个数组中分别取出一个数字,使得三个数字之间两两的绝对值差 不大于 d,问符合要求的有多少组合。(同一数组内,数字相同但下标不同的算多种方案)。

对于某个已经确定的数字 ai ,若在 [ ai - d , ai + d ] 的范围内选取 bj 和 ck,会发现可能不能满足 |bj - ck| ≤ d 的条件,因此不妨令 ai 为最小值,在 [ ai , ai + d ] 的范围内选取 bj 和 ck ,并统计符合该区间的 b 和 c 的个数,相乘即为以 ai 为最小值的组合数。

相同的方法应用到 bj 和 ck 上,但需要注意处理重复问题,即若以 bj 为最小值,而 ai 的取值为 [ bj , bj + d ] 时,会发现 ai 可以取到与 bj 相同的情况,而该情况是在处理以 ai 为最小值时已出现的,因此 ai 需要严格大于 bj 。同样的,在令 ck 为最小值时,需要令 ai 和 bj 严格大于 ck

由于给定的数组已排序,直接使用二分内置函数求满足要求的个数即可。

参考代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[500005], b[500005], c[500005];
int n, A, B, C;
int main(){
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    while(cin>>n>>A>>B>>C){
    
    
    	for(int i=0;i<A;i++)
    		cin>>a[i];
		for(int i=0;i<B;i++)
			cin>>b[i];
		for(int i=0;i<C;i++)
			cin>>c[i];
		ll ans=0;
		ll cnt1,cnt2;
		for(int i=0;i<A;i++){
    
    
			cnt1=upper_bound(b,b+B,a[i]+n)-lower_bound(b,b+B,a[i]);
			cnt2=upper_bound(c,c+C,a[i]+n)-lower_bound(c,c+C,a[i]);
			ans+=cnt1*cnt2;
			//cout<<cnt1*cnt2<<endl;
		}
		for(int i=0;i<B;i++){
    
    
			cnt1=upper_bound(a,a+A,b[i]+n)-upper_bound(a,a+A,b[i]);//此时a需要严格大于b 否则将于a状态重复 
			cnt2=upper_bound(c,c+C,b[i]+n)-lower_bound(c,c+C,b[i]);
			ans+=cnt1*cnt2;
			//cout<<cnt1*cnt2<<endl;
		}
		for(int i=0;i<C;i++){
    
    
			cnt1=upper_bound(a,a+A,c[i]+n)-upper_bound(a,a+A,c[i]);//此时满足a和b都严格大于c 
			cnt2=upper_bound(b,b+B,c[i]+n)-upper_bound(b,b+B,c[i]);
			ans+=cnt1*cnt2;
			//cout<<cnt1*cnt2<<endl;
		}
		cout<<ans<<endl;
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/laysan/article/details/121245692
今日推荐