11.6 模拟赛
复盘
What can i say. __ out.
T1 有点意思。发现答案上界是容易构造的。思路很快有了,代码差不多 5min 时写完并过大样例。
T2。好不容易看懂题面,好像一点思路没有,甚至暴力。
难点在于多个人可以同时操作多台密码机,这样爆搜复杂度岂不上天。过于困难先跳了。
T3。什么玩意,没给朴素暴力分?做不了一点啊。
T4。有 40 分的 \(\mathcal O(n^2 \log n)\) 是简单的。先写吧,目前只有这些分会了。
诶怎么感觉好熟悉……哦这不以前和以前某场模拟赛 T4 一模一样吗。但当时没补出来所以无所谓了。
写完了。尝试卡常通过 \(n \le 10^4\) 未果,跑了 6.667s(这个数我记得很清楚)。
做 T2 吧。
终于发现多个人可以同时操作多台密码机是假的。Never gonna give you up. 每个时刻大家都去做同一个一定更优啊。
那这不贪心思路就有了。好像挺对的直接开写。复杂度未知,写完就知道了。
\(\mathcal O(n^2)\)?那他 \(n \le 500\) 干啥?贪心感觉很对啊。
哦贪心假的,最后一个大样例没过。尝试在贪心的基础上乱搞未果。
好吧打部分分吧。状压是容易的,两个性质是容易的。这样就有 \(40\) 了。
不是怎么机房都会 T2。我想复杂了吗?都不会 T3 那我也不想了。
最终还是这些分。脑子不够啊。
预计 \(100+40+0+40=180\),结果 T1 1e6 的输入我用 cin T 啦。-= 50。
补题 \(100+100+60+40\)。
总结
cin 超时。以后无视数据范围闭眼加 ios,不要偷懒。
T3 应该可以想到 15 分的。
菜就多练。
知识点
- T1:数学;
- T2:贪心,DP;
- T3:DP 及优化;
- T4:数据结构。
A. 大副
令 \(m\) 的最高一位 \(1\) 在 \(k\) 上。
构造 \(\lfloor n/2\rfloor\) 个 \(2^k\),\(n-\lfloor n/2 \rfloor\) 个 \(2^k-1\),即可达到答案上界 \((2^{k+1}-1) \times \lfloor n/2\rfloor \times (n-\lfloor n/2 \rfloor)\)。
B. 机械师
首先 小甜水糖水不等式。多人同时破译多台机器是不优的。也即每个时刻都是所有人同时破译一台机器。
我们称最终变成机械玩偶的密码机为 B,只是破译的密码机为 A。
observasion 1:
一定先加工完所有 B 密码机后,再加工所有 A 密码机。
加工 B 密码机时一定按照 \(b_i\) 的递增顺序加工。
不妨枚举最终 B 密码机的数量 \(x\)。这样我们就能得到加工 A 时的速度。
将所有密码机按照 \(b_i\) 递增排序。那么最终的 B 密码机一定是按照编号顺序依次加工的。
此时做 DP。设 \(f(i, j, k)\) 表示前 \(i\) 个密码机中,有 \(j\) 个加工成 A,\(k\) 个加工成 B,最小花费时间是多少。
转移:
答案为 \(f(n, m-x,x)\)。其中 \(m\) 是原题给定的 \(k\)。
总复杂度 \(\mathcal O(n^4)\)。考虑优化。
observasion 2:
每个 B 密码机前面的所有密码机一定都被加工。
这是因为如果前面存在一个不被加工的,那么将这个加工成 B,原来的不加工,对后续的影响不变且效益更优(越往前 \(b\) 越小)。
所以状态里 \(j=i-k\) 是定值。状态数变成了 \(\mathcal O(n^2)\)。
考虑如何计算答案。不妨枚举最后一个 B 机器的位置 \(i\)。那么 \([1,i]\) 中一定有 \(i-x\) 个 A 和 \(x\) 个 B。A 的数量可能不够,还需要在 \([i+1,n]\) 中选择 \((m-x)-(i-x)=m-i\) 个。而这 \(m-i\) 个一定是 \(a\) 最小的。nth_element 即可。
总复杂度 \(\mathcal O(n^3)\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
int n, m;
struct Node {
int a, b;
}p[N];
float f[N][N]; // 前 i 个中,选了 j 个 A,k 个 B
int get(int x, int y) {
vector<int> v;
for (int i = x; i <= n; ++ i ) v.push_back(p[i].a);
nth_element(v.begin(), v.begin() + y, v.end());
int res = 0;
for (int i = 0; i < y; ++ i ) res += v[i];
return res;
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i ) {
cin >> p[i].a >> p[i].b;
if (p[i].b == -1) p[i].b = 1e9;
}
sort(p + 1, p + n + 1,
[&](Node x, Node y) {
return x.b == y.b ? x.a > y.a : x.b < y.b;
});
float res = 1e18;
for (int x = 0; x <= m; ++ x ) {
for (int i = 0; i <= n; ++ i )
for (int k = 0; k <= n; ++ k ) {
f[i][k] = 1e18;
}
f[0][0] = 0;
for (int i = 1; i <= n; ++ i ) {
for (int k = 0; k <= i && k <= x; ++ k ) {
int j = i - k;
if (j) f[i][k] = min(f[i][k], f[i - 1][k] + 1.0f * p[i].a / (x + 1));
if (k) f[i][k] = min(f[i][k], f[i - 1][k - 1] + 1.0f * p[i].b / k);
}
}
for (int i = x; i <= n; ++ i ) {
// i 是最后一个选 B 的位置
// 前面选了 i-x 个 A,后面还要补上 m-i 个
if (n - i >= m - i && m - i >= 0) {
res = min(res, f[i][x] + 1.0f * get(i + 1, m - i) / (x + 1));
}
}
}
cout << fixed << setprecision(3) << res << '\n';
}
signed main() {
freopen("mechanic.in", "r", stdin);
freopen("mechanic.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
#ifdef tests
cin >> T;
#endif
while (T -- ) solve();
return 0;
}

浙公网安备 33010602011771号