题目链接
题解
题意
一个矩阵一样的巧克力,取沿着副对角线切开后的上半部分(包含副对角线)。
开始沿着行/列吃巧克力,如果没有阻挡,就可以一口气吃完这一行/列。
一旦被吃的巧克力在下一次吃的那一行/列的路径上,就会形成阻挡,导致提前结束(原谅我蒟蒻的归纳能力)。
求每一次吃的巧克力的数量。
思路
分情况讨论一下:
假设所吃的行/列都没有被吃过:
- 第
i
列第j
行横向吃:遍历每一列k
,判断k
的终点(吃到的最后一块巧克力的位置)的行坐标m
和起点的行坐标n
与吃的这一行的行坐标j
的关系:如果j
位于这一区间则说明产生了阻挡且我们可以得知所能吃到的巧克力数量为 i − k i-k i−k; - 纵向吃同理。
如果该行/列已经被吃过则不能再吃,则吃到的巧克力数量为0
。
如果我们朴素地实现这一过程就会TLE
。
在上述方法中我们使用了区间,就会很麻烦。
通过分析,我们发现,对于行i
,被吃过的行中大于等于i
且距离i
最近的行j
所到达的终点必然是行i
所能到达的终点。
列同理。
在实现的过程中要注意如果某一列被吃了,那么这一列的起点的行坐标所在的行也被吃了,即这一行不能再吃了,它也要被加入到存储行的容器中。
列同理。
所以就是一个二分搜索嘛。
AC代码
#include <bits/stdc++.h>
using namespace std;
/// 被吃过的行/列的吃到的终点坐标
map<int, int> l, u;
int r, c;
char dire;
int n, m;
int ans = 0;
void eatU() {
/// 如果已经沿着这个方向吃过,就不能再吃了;
if (u.find(c) != u.end()) return;
auto p = u.lower_bound(c);
/// 如果没有比这个更大的,说明他可以吃完;
if (p == u.end()) {
ans = r;
} else {
ans = r - p->second;
}
/// 记录终点;
u[c] = r - ans;
l[r] = c;
}
void eatL() {
if (l.find(r) != l.end()) return;
auto p = l.lower_bound(r);
if (p == l.end()) {
ans = c;
} else {
ans = c - p->second;
}
l[r] = c - ans;
u[c] = r;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
scanf("%d%d", &n, &m);
while (m--) {
scanf("%d %d %c", &c, &r, &dire);
ans = 0;
if (dire == 'U') {
eatU();
} else if (dire == 'L') {
eatL();
}
printf("%d\n", ans);
}
return 0;
}
TLE代码
/**
* https://codeforces.ml/problemset/problem/555/C
* TLE
**/
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
int n, t;
int x, y;
char de;
/// first:col/row;second:num
map<int, int, greater<> > u, l;
int ans = 0;
void eatUp() {
bool flag = true;
for (auto it : l) {
if (it.first == x && it.second != 0) {
flag = false;
ans = 0;
break;
}
}
if (flag) {
/// 当前范围
int L = 1, R = y;
/// 理想情况下最多能吃的
ans = n - x + 1;
/// 遍历map,确定当前限制条件下少吃多少
for (auto it : u) {
int c = it.first, num = it.second;
/// 确定该条件下的范围
int l = (n + 1) - c - num + 1;
if (l <= x && L <= c && R >= c) {
ans -= (c - L + 1);
break;
}
}
if (l[x] < ans) l[x] = ans;
}
}
void eatLeft() {
bool flag = true;
for (auto it : u) {
if (it.first == y && it.second != 0) {
ans = 0;
flag = false;
break;
}
}
if (flag) {
int L = 1, R = x;
ans = n - y + 1;
for (auto it : l) {
int r = it.first, num = it.second;
int l = (n + 1) - r - num + 1;
if (l <= y && L <= r && r <= R) {
ans -= (r - L + 1);
break;
}
}
if (u[y] < ans) u[y] = ans;
}
}
void none() {
if (de == 'U') {
l[x] = y;
printf("%d\n", y);
} else if (de == 'L') {
u[y] = x;
printf("%d\n", x);
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
scanf("%d%d", &n, &t);
while (t--) {
scanf("%d %d %c", &x, &y, &de);
/// 第一次吃,此时两个map均为空。
if (u.empty() && l.empty()) {
none();
} else {
ans = 0;
if (de == 'U') {
/// 往上吃
eatUp();
} else if (de == 'L') {
///往左吃
eatLeft();
}
printf("%d\n", ans);
}
}
return 0;
}