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(i, j, k) = \min\begin{cases}f(i-1,j,k) & \\ f(i-1,j-1,k)+\frac{a_i}x & j \ne 0 \\ f(i-1,j,k-1)+\frac{b_i}k & i \ne 0 \end{cases} \]

答案为 \(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;
}

C. 小女孩

https://www.luogu.com.cn/article/sq3zwdth

posted @ 2024-11-06 15:19  2huk  阅读(52)  评论(1)    收藏  举报
2048 Game
Score
0
Best
0