题解:CF1612F Armor and Weapons

题意:很简单了,不再赘述。

做法:

注意到每次其实我们会做一个类似斐波那契的东西,所以我们猜答案是 \(O(\log n)\) 的。

但是我们会发现当 \(n>m\) 或者 \(n<m\) 很多的时候会爆掉,每次只能增加 \(O(\min(n,m))\),设 \(n<m\),则总次数是 \(O(\log n+\frac m n)\) 的,但是注意到 \(O(n)\times (\log n+\frac m n) = O(n\log n+m)\) 轻松可以通过,所以我们考虑枚举步数,然后用 \(O(n)\) 的时间去处理答案。

然后考虑我们每一次生成新的物品怎么样更优,我们发现选择铠甲和武器都是最大的一定最优,因为就算你将其中一个调小去凑一个特定的组合,他们最多多贡献 1,最多抵消调小的部分。

所以我们考虑 dp,\(dp_i\) 表示当前步数时,我们铠甲最高等级为 \(i\) 时,武器最高等级是多少。

那么我们肯定是用新产出的铠甲/武器去替换,那么就有转移式:

\[dp_i = \max(dp_i,i + dp_i + [(i,dp_i) 是一对组合]) \]

\[dp_{i + dp_i + [(i,dp_i) 是一对组合]} = \max(dp_{i + dp_i + [(i,dp_i) 是一对组合]}, dp_i) \]

做完了,给出代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e5 + 5;
int n, m, q, a[maxn], b[maxn], dp[maxn], dp2[maxn];
map<pair<int, int>, int> mp;
signed main() {
	cin >> n >> m >> q;
	for (int i = 1; i <= q; i++)
		cin >> a[i] >> b[i];
	if(n > m) {
		swap(n, m);
		for (int i = 1; i <= q; i++)
			swap(a[i], b[i]);
	}
	for (int i = 1; i <= q; i++)
		mp[make_pair(a[i], b[i])] = 1;
	dp[1] = 1;
	for (int i = 1; i; i++) {
		for (int j = 1; j <= n; j++) {
			if(!dp[j])
				continue;
			int v = j + dp[j] + mp[make_pair(j, dp[j])];
			dp2[j] = max(dp2[j], v);
		//	if(i <= 5) {
		//		cout << j << " " << dp[j] << " " << v << endl;
		//	}
			dp2[min(n, v)] = max(dp2[min(n, v)], dp[j]);
		}
		for (int j = n; j >= 1; j--)
			dp[j] = min(dp2[j], m), dp[j] = max(dp[j], dp[j + 1]), dp2[j] = 0;
	//	for (int j = 1; j <= n; j++)
	//		cout << dp[j] << " ";
	//	cout << endl;
		if(dp[n] == m) {
			cout << i << endl;
			return 0;
		}
	}
	return 0;
}
posted @ 2025-07-25 15:49  LUlululu1616  阅读(12)  评论(0)    收藏  举报