题解: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;
}

浙公网安备 33010602011771号