2024 CCPC 济南 + 山东省赛 VP 记录 + 个人题解 ACDEFHIJKM

五月份赛时写了五个题,这次(赛后三个月)个人 VP 了剩下的题目,耗时接近六个小时又写了五个题,括号里是 VP 的罚时,从 300 开始计,没有标记罚时的是五月份赛时写的。

一个人打很容易在一条路上走死,遇到 WA 也找不出 bug……六个小时有四个小时在想为什么 WA,有队友讨论检查的话罚时会少很多……

个人评价难度:

  • 签到:I
  • 比较基础,广义签到:AKJ
  • 略有思维难度:CF
  • 需要细心思考:DHM
  • 很天才的想法:EL
  • 暂时做不了的:BG

A. Printer

题意 n n n 台打印机,第 i i i 台打印机每 t i t_{i} ti 秒打印一份试题,但每次打印 l i l_{i} li 份试题后要休息 w i w_{i} wi 秒。如果所有打印机同时工作,打印 k k k 份题至少要多久。

数据范围: n ⩽ 100 n \leqslant 100 n100,其余数据 ⩽ 1 × 1 0 9 \leqslant 1\times10^{9} 1×109

思路 题目不难,二分答案即可。唯一考点在于二分要提前返回,否则会爆 LL。

时间复杂度 Θ ( n log ⁡ v ) \Theta(n\log v) Θ(nlogv),其中 v = 2 × 1 0 18 v=2\times 10^{18} v=2×1018

void eachT() {
   
	int n = read(), k = read();

	vector<ll> t(n), l(n), w(n);
	for (int i = 0; i < n; ++i) {
   
		t[i] = read(), l[i] = read(), w[i] = read();
	}

	auto check = [&](ll mid) {
   
		ll sum = 0;
		for (int i = 0; i < n; ++i) {
   
			ll q = mid / (t[i] * l[i] + w[i]), r = mid % (t[i] * l[i] + w[i]);
			sum += q * l[i] + min(r / t[i], l[i]);
			if (sum >= k) return true;
		}
		return false;
		// return sum >= k;  <- sum爆LL
	};

	ll lt = 1, rt = 2e18;
	while (lt <= rt) {
   
		ll mid = (lt + rt) >> 1;
		if (check(mid)) rt = mid - 1;
		else lt = mid + 1;
	}
	printf("%lld\n", lt);
}

C. Colorful Segments 2 (447 + 2)

题意 给定数轴上的 n n n 条线段,每条线段可以涂上 k k k 种颜色的一种,要求颜色相同的线段不能相交。求方案数。

数据范围: n ⩽ 5 × 1 0 5 n \leqslant 5\times 10^{5} n5×105,其余数据 ⩽ 1 × 1 0 9 \leqslant 1\times10^{9} 1×109

思路 按左端点排个序,然后依次染色,如果当前线段与已经染色的 t t t 条线段相交,对答案的贡献是 k − t k-t kt。将所有贡献乘起来。

如果用线段树,则是区间加、区间最大值,也可以用堆 (multiset) 维护。

时间复杂度 Θ ( n log ⁡ v ) \Theta(n\log v) Θ(nlogv),其中 v = 1 × 1 0 9 v=1\times 10^{9} v=1×109

constexpr int mod = 998244353;
constexpr int N = 5e5 + 8;

struct SMT {
   
	struct info {
   
		int mx;
		int mrk;
		int l, r;
	} t[N << 6];
	void push_up(info& p, info l, info r) {
   
		p.mx = max(l.mx, r.mx);
	}
	void push_down(info& p, int d, int l) {
   
		p.mx += d;
		p.mrk += d;
	}

	// ...
} smt;

void eachT() {
   
	int n = read(), k = read();
 
	vector<pair<int, int>> a(n);
	for (auto& [l, r] : a) {
   
		l = read(), r = read();
	}
	sort(a.begin(), a.end());
 
	smt.init(1, 1e9);
 
	ll res = 1;
	for (auto& [l, r] : a) {
   
		auto qq = smt.query(l, r);
		res *= k - qq.mx;
		res %= mod;
		smt.modify(l, r, 1);
	}
	printf("%lld\n", res);
}

D. Hero of the Kingdom (514 + 3)

队友比较擅长这种题,我自己做写得又慢错误率又高……

题意 买入 x x x 件商品需要 a x + b ax + b ax+b 秒和 p x px px 金币,卖出 x x x 件商品需要 c x + d cx + d cx+d 秒赚 q x qx qx 金币。有 t t t 秒以及初始 m m m 金币,问 t t t 秒结束后最多能有多少金币。

思路 首先有两个结论:尽可能多地买,最终全卖(否则可以不买)。于是问题化为花费 ( a + c ) x + ( b + d ) (a+c)x+(b+d) (a+c)x+(b+d) 秒赚 ( q − p ) x (q-p)x (qp)x 金币,其中 x ⩽ ⌊ m q ⌋ x \leqslant \lfloor \cfrac{m}{q} \rfloor xqm

思考能不能暴力模拟,不能。最坏情况 q − p = 1 q-p=1 qp=1,且 x x x 始终为 1 1 1,需要模拟大约 t t t 次,时间不允许。

进一步思考如何用计算代替模拟。如果 x x x 始终不变,我们可以把这一部分的模拟合并为一次,具体来说:

一次性最多买 x x x 个,且 p x ⩽ m < p ( x + 1 ) px \leqslant m<p(x+1) pxm<p(x+1),要求 x x x 始终不变,设这样最多买 l l l 轮次后 x x x 才会变化,有 m + ( q − p ) x ⋅ l ⩾ p ( x + 1 ) m+(q-p)x\cdot l \geqslant p(x+1) m+(qp)xlp(x+1),化简得 l = ⌈ p ( x + 1 ) − m ( q − p ) x ⌉ l=\left\lceil \cfrac{p(x+1)-m}{(q-p)x} \right\rceil l=(qp)xp(x+1)m

那买 l l l 轮的时间够吗?不一定,需要满足 l ⋅ [ ( a + c ) x + ( b + d ) ] ⩽ t l\cdot[(a+c)x+(b+d)] \leqslant t l[(a+c)x+(b+d)]t,因此 l l l

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值