Live2D

Solution -「CTSC 2018」「洛谷 P4602」混合果汁

Description

  Link.

  n 种果汁,第 i 种美味度为 di,每升价格 pi,一共 li 升。m 组询问,给定花费上限 g 和果汁需求量 L,求混合多种果汁以满足要求时,所用果汁最小美味度的最大值。

  n,m,pi105

Solution

  最小值最大,显然二分。

  需要 check:能否用美味度不小于 mid 的果汁混合出 L 升,使得价格不超过 g

  没有美味度的限制,贪心地用单价更低的果汁就好啦!

  回归到原问题,以按美味度降序排列后的果汁编号为版本轴建主席树,树是以单价为下标的权值线段树。外层二分出 mid,再在以 mid 为根的树上走,贪心地购买果汁(先买左子树,不够再去右子树)。

  就完了 qwq。复杂度 O(nlog2n)

Code

#include <cstdio>
#include <algorithm>

const int MAXN = 1e5;
int n, m, root[MAXN + 5];

typedef long long LL;

inline LL rint () {
	LL x = 0; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () );
	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
	return x;
}

struct Juice {
	int d, p, l;
	inline void read () { d = rint (), p = rint (), l = rint (); }
	inline bool operator < ( const Juice t ) const { return d > t.d; }
} juice[MAXN + 5];

struct PersistentSegmentTree {
	static const int MAXND = MAXN * 40;
	int cntnd, ch[MAXND + 5][2];
	LL sum[MAXND + 5], prc[MAXND + 5];

	inline void build ( int& rt, const int l, const int r ) {
		rt = ++ cntnd;
		if ( l == r ) return ;
		int mid = l + r >> 1;
		build ( ch[rt][0], l, mid ), build ( ch[rt][1], mid + 1, r );
	}

	inline void pushup ( const int rt ) {
		sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
		prc[rt] = prc[ch[rt][0]] + prc[ch[rt][1]];
	}

	inline void insert ( int& rt, const int l, const int r, const int p, const int v ) {
		int old = rt, mid = l + r >> 1; rt = ++ cntnd;
		ch[rt][0] = ch[old][0], ch[rt][1] = ch[old][1], sum[rt] = sum[old], prc[rt] = prc[old];
		if ( l == r ) return sum[rt] += v, prc[rt] += 1ll * v * p, void ();
		if ( p <= mid ) insert ( ch[rt][0], l, mid, p, v );
		else insert ( ch[rt][1], mid + 1, r, p, v );
		pushup ( rt );
	}

	inline LL buy ( const int rt, const int l, const int r, LL money, LL need ) {
		if ( sum[rt] < need || money < 0 ) return -1;
		if ( l == r ) return need * l <= money ? need * l : -1;
		int mid = l + r >> 1;
		if ( sum[ch[rt][0]] >= need ) return buy ( ch[rt][0], l, mid, money, need );
		else {
			LL t = buy ( ch[rt][1], mid + 1, r, money - prc[ch[rt][0]], need - sum[ch[rt][0]] );
			return ~ t ? t + prc[ch[rt][0]] : -1;
		}
	}
} pst;

int main () {
	n = rint (), m = rint ();
	int mxp = 0;
	for ( int i = 1; i <= n; ++ i ) {
		juice[i].read ();
		if ( mxp < juice[i].p ) mxp = juice[i].p;
	}
	std::sort ( juice + 1, juice + n + 1 );
	pst.build ( root[0], 1, mxp );
	for ( int i = 1; i <= n; ++ i ) {
		pst.insert ( root[i] = root[i - 1], 1, mxp, juice[i].p, juice[i].l );
	}
	for ( LL g, L; m --; ) {
		g = rint (), L = rint ();
		int l = 1, r = n;
		LL ans = -1, tmp;
		while ( l <= r ) {
			int mid = l + r >> 1;
			if ( ~ pst.buy ( root[mid], 1, mxp, g, L ) ) r = ( ans = mid ) - 1;
			else l = mid + 1;
		}
		printf ( "%d\n", ~ ans ? juice[ans].d : -1 );
	}
	return 0;
}
posted @   Rainybunny  阅读(112)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示