《P4602 [CTSC2018] 混合果汁》

题目描述

小 R 热衷于做黑暗料理,尤其是混合果汁。

商店里有 n 种果汁,编号为 0,1,⋯,n−1 。i 号果汁的美味度是 di​,每升价格为 pi​。小 R 在制作混合果汁时,还有一些特殊的规定,即在一瓶混合果汁中,i 号果汁最多只能添加 li​ 升。

现在有 m 个小朋友过来找小 R 要混合果汁喝,他们都希望小 R 用商店里的果汁制作成一瓶混合果汁。其中,第 j 个小朋友希望他得到的混合果汁总价格不大于 gj​,体积不小于 Lj​。在上述这些限制条件下,小朋友们还希望混合果汁的美味度尽可能地高,一瓶混合果汁的美味度等于所有参与混合的果汁的美味度的最小值。请你计算每个小朋友能喝到的最美味的混合果汁的美味度。

输入格式

输入第一行包含两个正整数 n,m,表示果汁的种数和小朋友的数量。

接下来 n 行,每行三个正整数 di​,pi​,li​,表示 i 号果汁的美味度为 di​,每升价格为 pi​,在一瓶果汁中的添加上限为 li​。

接下来 m 行依次描述所有小朋友:每行两个数正整数 gj​,Lj​ 描述一个小朋友,表示他最多能支付 gj​ 元钱,他想要至少 Lj​ 升果汁。

输出格式

对于所有小朋友依次输出:对于每个小朋友,输出一行,包含一个整数,表示他能喝到的最美味的混合果汁的美味度。如果无法满足他的需求,则输出 −1。

输入输出样例

输入 #1复制

复制代码
3 4
1 3 5
2 1 3
3 2 5
6 3
5 3
10 10
20 10

输出 #1复制

复制代码
3
2
-1
1

说明/提示

对于所有的测试数据,保证 n,m≤100000,1≤di​,pi​,li​≤105,1≤gj​,Lj​≤1018。

测试点编号 n= m= 其他限制
1,2,3 10 10
4,5,6 500 500
7,8,9 5000 5000
10,11,12 100000 100000 pi​=1
13,14,15 100000 100000 li​=1
16,17,18,19,20 100000 100000

代码实现:

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>

#define N 100005
#define INF 0x3f3f3f3f

using namespace std;

inline int rd(){
	int x=0,y=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return y?-x:x;
}
template<typename T>
inline T rd(){
	T x=0;
	int y=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return y?-x:x;
}

int rt[N];
struct drink{
	int d, l, rk;
	long long p;
}dr[N];

struct ct{
	int lc[N<<5], rc[N<<5], cnt;
	long long s[N<<5], c[N<<5], val[N<<5];
    // s: l*p的和, c: l的和, val: 叶子节点的p
#define lc(x) lc[x]
#define rc(x) rc[x]
	void build(int pos, int l, int r, int &nd, int old, long long L, long long P){
		nd=++cnt;
		s[nd]=s[old]+L*P;
		c[nd]=c[old]+L;
		if(l==r){
			val[nd]=P;
			return;
		}
		int mid=l+r>>1;
		if(pos<=mid)rc(nd)=rc(old),build(pos,l,mid,lc(nd),lc(old),L,P);
		else lc(nd)=lc(old),build(pos,mid+1,r,rc(nd),rc(old),L,P);
	}
	long long qry(int l, int r, int nd, long long g){
		if(l==r)return nd?min((g/val[nd]),c[nd]):0;
		int mid=l+r>>1;	
		if(s[lc(nd)]>g)return qry(l,mid,lc(nd),g);
		else return qry(mid+1,r,rc(nd),g-s[lc(nd)])+c[lc(nd)];
	}
}tr;

inline bool cmp1(drink x, drink y){return x.p < y.p;}
inline bool cmp2(drink x, drink y){return x.d > y.d;}

int main(){
	int n=rd(), m=rd();
	for(register int i=1;i<=n;++i)
		dr[i].d=rd(), dr[i].p=rd<long long>(), dr[i].l=rd();
	sort(dr+1, dr+1+n, cmp1);
	for(register int i=1;i<=n;++i)dr[i].rk=i;
	sort(dr+1, dr+1+n, cmp2);
	for(register int i=1;i<=n;++i)
		tr.build(dr[i].rk, 1, n, rt[i], rt[i-1], dr[i].l, dr[i].p);
	
	int l, r;
	while(m--){
		long long g=rd<long long>(), L=rd<long long>();
		int ans=-1;
		l=1, r=n;
		while(l<=r){
			int mid=l+r>>1;
			long long k=tr.qry(1, n, rt[mid], g);
			if(k>=L)ans=dr[mid].d, r=mid-1;
			else l=mid+1;
		}
		printf("%d\n", ans);
	}
	return 0;
}
相关推荐
linx29526 分钟前
单元九 · 零基础路线图-第 7–9 周·类与 RAII
c语言·开发语言·数据结构·c++·嵌入式硬件·算法
布莱克60529 分钟前
C++ 七大排序算法详解:选择、冒泡、插入、计数、堆、快速与归并排序
数据结构·c++·算法·排序算法
shehuiyuelaiyuehao1 小时前
算法44,模拟算法,数青蛙
算法·哈希算法·散列表
hanlin031 小时前
刷题笔记:力扣第287题-寻找重复数
笔记·算法·leetcode
kevin_kang2 小时前
第02章 对话时间线与延迟分析
算法
科学实验家2 小时前
最小生成树:Prim,kruskal
数据结构·c++·算法
学习智者2 小时前
《玄》IDE v3.6.3重磅发布:全功能修复与性能飞跃
开发语言·c++·ide·算法·中文语言 玄
Jasmine_llq2 小时前
《P10263 [GESP202403 八级] 公倍数问题》
算法·数论·快速 io 优化·埃氏筛(倍数枚举)·线性遍历求和
橘子汽水1682 小时前
Leetcode 322 279 零钱兑换,完全平方数
算法·leetcode
kevin_kang2 小时前
第01章 VoiceAgent 的总体架构与完整流程
算法