codeforces 857 D (初始化歪了,错失上分良机)

题目
题意: 给定n个商店,每个商店要么买A物品要么买B物品,不能不买。如何使得A物品的最大值与B物品的最大值之间的差值最小。即 minimize | max(A) - max(B)) |
思路: 和队友一起打的,刚开始没啥思路,后来一讨论我就有思路了,然后自己fst队友ac。最近光玩饥荒没敲过代码,属实下饭。后来发现最大值变量初始化成0了,默认B的最大值是0,改成初始化为-1秒ac,寄。
思路是包含贪心、双指针、二分的东西。
对于A物品从大到小枚举每个物品i当最大值,此时会发现,第i个商店必须选A,而价值比A[i]大的商店必须买B物品,可以维护出B物品的最大值至少是mx,而其余的物品既可以选A也可以选B。在其余的商店里,如果选B能使答案更优秀,就选对应的B,否则就选A,不会使结果更差。根据mx和A[i]的关系分情况讨论,如果mx更大,答案只能是mx-A[i];如果mx更小,可以在B中找比A[i]大和小的位置,看能否使答案更优。
PS: 如果二分的位置恰好是第i个商店,要移动一个下标。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int N = 5e5+10;
int n,m,k,T;
int a[N],b[N];
PII va[N],vb[N];
void solve()
{
	int ans = 2e9;
	cin>>n;
	for(int i=0;i<n;++i) cin>>a[i]>>b[i],va[i] = {a[i],i},vb[i] = {b[i],i};
	sort(va,va+n);
	sort(vb,vb+n);
	int r = n-1;
	int mx = -1; //b商店的最大值 
	for(int i=n-1;i>=0;--i)
	{
		int x = va[i].first; //最大值 
		int idx = va[i].second; //哪家商店固定买a 
		if(i<n-1&&x<va[i+1].first)
		{
			while(r>i) 
			{
				int wh = va[r].second; //哪家商店必须选b 
				mx = max(mx,b[wh]);
				r--;
			}
		}
//		cout<<i<<":"<<mx<<" "<<x<<"\n";
		if(mx<x) //选离x最近的 
		{
			int idx1 = lower_bound(vb,vb+n,make_pair(x,1000000000))-vb; //大于等于 
			int idx2 = idx1-1; //小于
//			cout<<idx1<<"???\n";
			if(idx1>=0&&idx1<n&&vb[idx1].second==idx) idx1++; //恰好是选a的商店 
			if(idx2>=0&&idx2<n&&vb[idx2].second==idx) idx2--; //恰好是选a的商店 
			int d1 = 2e9,d2 = 2e9,d3 = 2e9;
//			cout<<idx1<<":"<<vb[idx1].first<<"\n";
			if(idx1>=0&&idx1<n&&vb[idx1].second != idx) d1 = vb[idx1].first - x;
			if(idx2>=0&&idx2<n&&vb[idx2].second != idx && vb[idx2].first > mx) d2 = x - vb[idx2].first;
			if(mx!=-1) d3 = x-mx;
			ans = min({ans,d1,d2,d3});
		}
		else //没法选更优 
		{
			ans = min(ans,mx-x);
		}
	}
	cout<<ans<<"\n";
}
signed main(void)
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>T;
	while(T--) solve();
	return 0;
}
/*
2
2
0 0
1 2
2
10 100
10 100
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值