AtCoder Beginner Contest 005
A
输入正整数 \(x, y\) 。输出 \(\lfloor \frac{y}{x} \rfloor\) 。
B
输入 \(a_1, a_2, \cdots, a_n\) 。输出 \(min\{a_i\},(1 \leq i \leq n)\) 。
C
题意
一个章鱼烧只能留存 \(T\) 秒。
\(N\) 个章鱼烧的顺序出炉时间是 \(a_1, a_2, \cdots, a_N\) 。
\(M\) 个顾客顺序到达的时间是 \(b_1, b_2, \cdots, b_M\) 。
顾客达到时若恰好不能买章鱼烧就会离去,询问是否所有顾客都能买到章鱼烧。
题解
这是比较明显的先入先出,由于后入的有更多购买章鱼烧的机会,所以贪心让先入的购买。
根据先入先出的性质,对顾客维护一个普通队列。枚举章鱼烧的出炉时间。
每次把失去耐心离开的顾客全部出队,此时若队首的顾客此时已经到达,则让他购买这个章鱼烧,答案加一。
时间复杂度 \(O(n + m)\) 。
view
另一种更直观但复杂度更高的解法。
我们可以让源点 \(s\) 向所有章鱼烧连一条容量为 \(1\) 的边,让所有顾客向汇点 \(t\) 连一条容量为 \(1\) 的边。
对于任意一个章鱼烧,查询所有顾客,从出炉时间到过期时间来的所有顾客,都连接一条容量为 \(1\) 的边。
建图复杂度 \(O(n^{2})\) 。
然后用 \(Dinic\) 求最大流,在二分图中的时间复杂度只需要 \(O(n \sqrt{m}) = n^{2}\) 。
这题的 PRO 版本
将这题的 \(T\) 改成 \(T_1, T_2, \cdots, T_m\) 表示每个顾客的等待时间。那么最终有多少顾客可以买到章鱼烧?
暴力的做法?
依旧可以选择 \(O(n^{2})\) 的网络流二分图做法。
更快的做法?
首先它没有了先入先出的性质。
考虑 \(T_i\) 不同,于是不再有先入先出的性质,不能直接使用队列。
观察到:每个顾客覆盖了一段 \([b_i, b_i + T_i]\) 的区间。
依旧考虑贪心将章鱼烧分配给最早离开的人,则在线算法实现很困难,考虑离线算法。
不妨重定义为 \(([\{st_i, 0\}, \{ed_i + 1, 1\}))\) ,表示左开右闭区间和区间种类。
将 \(2m\) 个区间端点按照升序排序,则构成了一个维度的偏序。左闭区间为加入点,右开区间为删除点。
将 \(n\) 个章鱼烧的出炉点作为询问点。
于是这就是一个一维偏序的离线扫描问题。
首先将 \(2m + n\) 个时间离散化,再对时间开树状数组,利用区间修改维护每个点被多少顾客区间覆盖,记这个值为 \(val\) 。
设能够被购买的章鱼烧为 \(ans\) ,它在每个询问点所在的区间内最多增加 \(val\) 次。
动态维护 \(cnt\) 为购买了当前区间内章鱼烧的顾客数量,删去一个点时 \(cnt = max(cnt - 1, 0)\) 。
遇到一个询问点时,若 \(cnt < val\) ,则 \(cnt = cnt + 1\) ,\(ans = ans + 1\) 。
最后 \(ans\) 即能买到章鱼烧的顾客的最大数。
另一个题。
一开始因为翻译问题会错了题意。把“一个章鱼烧能留存 \(t\) 秒”理解成了“卖一个章鱼烧需要 \(t\) 秒”。
这样依旧会是一个有意思的题。
解法是:
- 把 \(a_i\) 作为左括号,\(b_i\)作为右括号,将它们按时间排序。
那么从第一个括号起,到最后一个右括号,这段括号序列一定得是个合法的括号序列。
只有这样每个顾客都有可能性买到章鱼烧。问题在于一个顾客到场时,章鱼啥的数量是够的,但是此时老板正在卖给别人。那么这个顾客不会等。
由于卖卖章鱼烧的行为如果能够发生,是在一个顾客达到时立刻发生。那么只需要:
- 每个相邻两个右括号的差值 \(\geq t\) 。
时间复杂度 \(O(n)\) 。
D
diffculty 1447
题意
章鱼烧摸具是 \(N \times N\) 的,第 \((i, j)\) 个位置可以放置一个章鱼烧,烤出的美味度是 \(a_{i, j}\) 。
存在 \(Q\) 个员工,每个员工一次能烤的章鱼烧上限为 \(P_1, P_2, \cdots, P_Q\) 。
烤一次章鱼烧一定要在摸具中选择一个矩形区域,且每个位置都要放满章鱼烧。
询问每个员工一次能烤出的章鱼烧的美味度之和最大值。
\(N \le 100\) 。
题解
首先使用二维前缀和处理,以便能够 \(O(1)\) 回答任意一个矩形的权值和。用时 \(O(N^{2})\) 。
维护 \(f[i]\) 为烤 \(i\) 个章鱼烧能够得到的最大美味度之和,
然后 \(O(N^{4})\) 枚举矩形的四个边界计算权值和,设面积为 \(S\) ,更新 \(f[S]\) 。
最后让 \(g[i] = max(f[i - 1], g[i])\) ,\(g[i]\) 代表烤不超过 \(i\) 个章鱼烧能够得到的最大美味度之和。
注意到 \(P_i > n \times n\) 没有意义,回答时让 \(P_i\) 与 \(n \times n\) 取 \(min\) 。
总时间复杂度 \(O(N^{4})\) 。
view
int n; std::cin >> n;
const int m = n;
std::vector<std::vector<int> > g(n + 1, std::vector<int>(m + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
std::cin >> g[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
g[i][j] += g[i][j - 1];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
g[i][j] += g[i - 1][j];
}
}
std::vector<int> f(n * m + 1, 0);
for (int up = 1; up <= n; up++) {
for (int down = up; down <= n; down++) {
for (int left = 1; left <= m; left++) {
for (int right = left; right <= m; right++) {
int S = (down - up + 1) * (right - left + 1);
f[S] = std::max(f[S], g[down][right] - g[up - 1][right] - g[down][left - 1] + g[up - 1][left - 1]);
}
}
}
}
for (int i = 1; i <= n * m; i++)
f[i] = std::max(f[i], f[i - 1]);
int Q; std::cin >> Q;
for (int i = 0; i < Q; i++) {
int x; std::cin >> x;
x = std::min(x, n * m);
std::cout << f[x] << "\n";
}
浙公网安备 33010602011771号