codeforces 767 D. Cartons of milk(二分+贪心+双指针)

本文解析了一道Codeforces D级难度题目,涉及牛奶购买策略,通过贪心算法结合二分查找优化解决大规模数据处理问题,避免TLE。分享了双指针技巧与高效检查策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://codeforces.com/contest/767/problem/D
题意:自己已经拥有n瓶牛奶,每瓶保质期已知,超市有m瓶牛奶,保质期已知,每天喝掉k瓶牛奶,不足k瓶全部喝光,过期牛奶就会扔掉,问最多买多少牛奶可以不用扔掉

思路:自然能想到购买的时候贪心的买,从保质期大的开始买,如果保质期大的都需要扔掉,那么自然保质期小的也需要扔掉,那么这个牛奶数目就可以通过二分来check
关键问题这道题数据偏大,如果每次检查答案把所有牛奶拿出来重新排序的话会TLE(可能我写的太菜)
比较优秀的写法是通过最初将b数组排序,每次二分最初购买的位置x,然后检查x-n都购买是否符合要求,check的时候采用双指针,哪一个优小优先选择哪一个,如果一个选完只能选择另一个,然后用一个day记录当前天数,如果现在喝的小于day那么自然不符合要求

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
using namespace std;
 
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, int> LP;
const int inf = 0x3f3f3f3f;
const int N = 1e7 + 100;
const ll mod = 1e18+7;
const int base=131;
inline ll mul(ll x,ll y) { return (x*y-(ll)((long double)x*y/mod)*mod+mod)%mod;}
inline ll ksm(ll a,ll b) {ll ans=1;while(b){if(b&1)ans=mul(ans,a);a=mul(a,a),b>>=1;}return ans;}
 
 
ll n,m,k,x,y,cx,cy,t;
ll ans,cnt,sum,flag,res;
 
ll a[N];//,b[N];
ll num[N];
 
//ll tree[N];
string s;
 
//vector<int> v[N];
 
ll mx;
 
P b[1000005];
bool cmp(P a,P b)
{
	return a.fi<b.fi;
}
bool check(ll x)
{
	int i=0,j=x,day=0;
	int tk=k;
	while(i<n||j<m)
	{
 
		if(a[i]<b[j].fi&&i<n||j==m)
		{
			if(a[i]<day) return 0;
			tk--;
			i++;
		}
		else
		{
			if(b[j].fi<day) return 0;
			tk--;
			j++;
		}
		//show3(i,j,day)
		if(tk==0) day++,tk=k;
	}
	return 1;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
 
	cin>>n>>m>>k;
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<m;i++) cin>>b[i].fi,b[i].se=i+1;
	sort(a,a+n);
	sort(b,b+m,cmp);
 
	int l=0,r=m;
	ans=-1;
	while(l<=r)
	{
		int mid=l+r>>1;
		if(check(mid))
		{
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	if(ans==-1) return cout<<-1,0;
	cout<<m-ans<<endl;
	for(int i=ans;i<m;i++)
	{
		cout<<b[i].se<<" ";
	}
	//cout<<check(0)<<endl;
 
 
}
/*
数据范围
是否爆int
空间大小
时间复杂度
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值