Codeforces Round 995 (Div. 3) D. Counting Pairs

D. Counting Pairs

题目:



中文翻译 :

                                                         D. 计数对

每个测试的时间限制为2秒 每个测试的内存限制为256兆字节 给定一个由n个整数组成的序列a,其中序列的第i个元素等于ai。同时给定两个整数x和y(x≤y)。

如果整数对(i,j)满足以下条件,则认为该对是有趣的:

1≤i<j≤n; 如果同时从序列a中移除位置i和j的元素,剩余元素的和至少为x且至多为y。 你的任务是确定给定序列a中有趣整数对的数量。

输入 第一行包含一个整数t(1≤t≤10^4)——测试用例的数量。

每个测试用例包含两行:

第一行包含三个整数n,x,y(3≤n≤2⋅10^5,1≤x≤y≤2⋅10^14); 第二行包含n个整数a1,a2,…,an(1≤ai≤10^9)。 输入的额外约束:所有测试用例中n的总和不超过2⋅10^5。

输出 对于每个测试用例,输出一个整数——给定序列a中有趣整数对的数量。

思路 :

我们可以用 brute force 即暴力的方法,枚举二元组 (i,j)i < j 。然而时间复杂度是O(n*n),

会出现 tle 的情况 。那么怎么将他优化 ?

   设sum 表示 arry 的和 , 那么要解决的问题就是  x <=  sum-ai-aj  <= y  ,我们可以一维的枚举

   ai , 在知道ai 的情况下,我们要寻找相应符合的 aj ,可以将x <=  sum-ai-aj  <= y  改写为 : 

sum-y-ai  <=  aj  <=  sum-ai-x  ,那么我们的任务是查找符合上试的 aj ,关于查找,一种很常见的优化时间的方法是 binery search ! (二分) 时间复杂度是 O(log n ),但是我们用二分之前需要先构造单调性,我们可以很容易观察到: 符合条件的 i,j  ,与其相对应相对位置无关,所以我们可以用 sort 进行排序 ( 复杂度 :O(n*log n )), 然后遍历 数组 枚举 ai,寻找aj的lower bound 和upper bound ,但是要注意 寻找的时候  要保证 i < j , 所以找出上下界之后还要一些处理。   

C++  ACcode :

#include<bits/stdc++.h>
#define int long long 
using namespace std;

int t,n,x,y;

signed main()
{   
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>t;
	
	auto solve = [&](){
		cin>>n>>x>>y;          // x <= y
		vector<int> a(n+100);
		int s=0;
		for(int i=1;i<=n;++i){
			cin>>a[i];
			s+=a[i];
		}
		
		sort(a.begin()+1,a.begin()+1+n);
		
		auto aj_r = [&](int xx){   
			/* wa point 1 and debug : 
			       variation x is using for public , 
			       but perviously I created              
			       a variatione and the name is same with x ,
			       leading to ambiguous*/
			int l=1,r=n,res=0;
			while(l<=r){
				int mid=(l+r)>>1;
				if(a[mid]<=s-x-a[xx]){
					res=mid;
					l=mid+1;
				}
				else r=mid-1;
			}
			return res;
		};
		
		auto aj_l = [&](int xx){
			int l=1,r=n,res=0;
			while(l<=r){
				int mid=(l+r)>>1;
				if(a[mid]>=s-y-a[xx]){
					res=mid;
					r=mid-1;
				}
				else l=mid+1;
			}
			return res;
		};
		
		int ans=0;  /* we should avoid to repreatly chose ai ,and aj,
		            since i<j ,and ai<=aj ,so we should pay attention to
		            determain the lowerbound --> l; */
		for(int i=1;i<=n;++i){
			int l=aj_l(i);
			int r=aj_r(i);
		/*	cout<<"------"<<'\n';
		    cout<<x<<"<="<<s-a[i]-a[l]<<"<="<<y<<'\n';
			cout<<x<<"<="<<s-a[i]-a[r]<<"<="<<y<<'\n';
	    	cout<<"-----"<<'\n';	
	    	if(l==i) l++,cout<<"ca0"<<'\n'; */
			l= i>=l? i+1:l;  // detail should be pay more attention to !
		    if(l==0||r==0||r<=i||l>r) continue ;
		/*	wa point 2 ans debug :
			why could not without this if(empression) ?	? ? ? ? */
			int sl=s-a[i]-a[l];
			int sr=s-a[i]-a[r];
			if(!(x<=sl&&sl<=y)&&!(x<=sr&&sr<=y)) continue ;
		/*      why shound add this (if mantain)  to keep the ans ? ? ? ? 	
	    		cout<<"------"<<'\n';
			    cout<<x<<"<="<<s-a[i]-a[l]<<"<="<<y<<'\n';
				cout<<x<<"<="<<s-a[i]-a[r]<<"<="<<y<<'\n';
			    cout<<i<<" "<<l<<" "<<r<<'\n';
				cout<<"-----"<<'\n';
			    cout<<"+"<<r-l+1<<'\n';  */
			   ans+=r-l+1;
		}
		
		cout<<ans<<'\n';
	};
	
	while(t--) solve();
	return 0;
}
### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值