Codeforces Round #753 (Div. 3)

Keywords: greedy algorithm search engine dfs CodeForces

There are three main situations:

  • It's been a second since I took a look at my beard. The implementation is also very simple. I write casually / too lazy to write
  • After a second, I felt that it would not be realized, so I went to look at other people's code
  • I didn't understand the question

A

Direct simulation.

B

Simple math problems + find rules, but a little reading comprehension

C

I always feel that this problem has been done. Anyway, it is a simple problem. Just save the global subtraction with a mark.

D. Blue-Red Permutation

It's an interesting greedy question, although it's also a simple one. Note that Red can be bigger, let it be as big as possible; Blue can be made smaller, so make it as small as possible.

const int MAXN = 2e5 + 10;

int n;
int aa[MAXN];
std::vector<int> blues, reds;
std::string s;

void _main() {
    cin >> n;
    rep (i, 1, n) {
        cin >> aa[i];
    } cin >> s;
    rep (i, 1, n) {
        if (s[i - 1] == 'B') blues.push_back(aa[i]);
        else reds.push_back(aa[i]);
    }
    bool ans = true;
    std::sort(ALL(blues)); std::sort(ALL(reds));
    // blue: decrease, place at 1 ~ siz(blue)
    int ind = 1;
    for (auto v : blues) {
        if (v < ind) ans = false;
        ++ind;
    }
    // red: increase, place at siz(blue) + 1 ~ n
    for (auto v : reds) {
        if (v > ind) ans = false;
        ++ind;
    }
    cout << (ans ? "YES" : "NO") << endl;
    blues.clear(); reds.clear();
}

int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T --> 0) {
        _main();
    }
    return 0;
}

E. Robot on the Board 1

It's easy to think of recording how far up, down, left and right have been expanded, and then give a judgment.

However, I felt a little solidified in my mind. The initial idea was to finish all the operations first, and then go back one by one. I didn't expect that I could judge while walking directly, which exceeded the direct output of the answer.

F. Robot on the Board 2

Seeing that there was no solution in the valley, he was angry

Start with search

First of all, when we see this topic, we can naturally think of how to use violence: search for each grid from the current point.

But there are many steps in this process, and the search is unnecessary: starting from a grid, the last stop position is certain, so if this grid is searched again, what are we going to do with searching it? Just use the information we already know?

So we consider the idea of memory: record a dist[i][j] to represent the maximum number of instructions that can be executed from position (i, j).

Next, we start searching from a starting point that has not been searched until we meet a grid we have passed before. There are three situations for this end:

  • Jump out of map boundary
  • Go to the grid passed by this search, that is, into a ring
  • Go to the previous grid

Let's discuss:

Jump out of map boundary

The picture is drawn with Excel

This situation is very simple. We can update dist in the reverse order of the path.

Out of the ring

In this case, starting from all points on the ring, you can go around the ring, so the answer to the point on the ring is the ring length; The points outside the ring update dist in the reverse order of the path.

Go to where you used to go

It can be found that the answer can be directly inherited from the points we have passed before, and the dist can be updated in reverse order according to the path order.

code implementation

const int MAXN = 2000 + 10;

const std::string drr = "RLDU";
const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};

int n, m;
char mat[MAXN][MAXN];

int dist[MAXN][MAXN];
bool vis[MAXN][MAXN];

void SearchGetPath(std::vector<std::pair<int, int> > &path, int &x, int &y) {
    while (!(x < 1 || y < 1 || x > n || y > m || vis[x][y])) {
        // DEBUG(x); DEBUG(y);
        vis[x][y] = true;
        path.push_back({x, y});
        int dr = (int) (drr.find(mat[x][y]));
        x += dx[dr]; y += dy[dr];
    }
}

void _main() {
    cin >> n >> m;
    rep (i, 1, n) cin >> (mat[i] + 1);
    rep (x, 1, n) rep (y, 1, m) {
        dist[x][y] = -1;
        vis[x][y] = 0;
    }
    rep (x, 1, n) rep (y, 1, m) if (dist[x][y] == -1) {
        int nx = x, ny = y; std::vector<std::pair<int, int> > path;
        SearchGetPath(path, nx, ny);
        if (nx < 1 || ny < 1 || nx > n || ny > m) {
            // Jump out of map boundary
            path.push_back({nx, ny});
            dist[nx][ny] = 0;
            for (int i = (int) path.size() - 2; i >= 0; --i) {
                dist[path[i].fi][path[i].se] = dist[path[i + 1].fi][path[i + 1].se] + 1;
            }
        } else {
            // Ring length
            int circlesize = (int) (path.end() - std::find(ALL(path), std::make_pair(nx, ny)));
            if (circlesize == 0) {
                // This is not a ring, it's a path we've taken before
                path.push_back({nx, ny});
                for (int i = (int) path.size() - 2; i >= 0; --i) {
                    dist[path[i].fi][path[i].se] = dist[path[i + 1].fi][path[i + 1].se] + 1;
                }
                continue;
            }
            int i = path.size() - 1;
            int step = 1; // For a small trick, the answer is circle when it is on the ring and step when it is outside the ring
            for (i = path.size() - 1; i >= 0; --i) {
                dist[path[i].fi][path[i].se] = std::max(step, circlesize);
                ++step;
            }
        }
    }
    int ax = 0, ay = 0;
    rep (i, 1, n) rep (j, 1, m) {
        if (dist[i][j] > dist[ax][ay]) {
            ax = i; ay = j;
        }
    }
    cout << ax << ' ' << ay << ' ' << dist[ax][ay] << endl;
}

int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T --> 0) {
        _main();
    }
    return 0;
}

G. Banquet Preparations 1

This topic is still a little reading comprehension. Before reading the solution, I didn't understand what the topic was talking about. I thought it was to minimize the balance of the taster

The meaning of the question is to ask you for a group of \ (n \) \ (x_i \) so that:

\[\left|\sum_{i = 1}^n(a_i - x_i) - \sum_{i = 1}^n(b_i - (m - x_i))\right| \]

This thing is the smallest.

Simplify the following formula first:

\[\left|\sum_{i = 1}^n(a_i - b_i + m) - 2\sum_{i = 1}^n x_i\right| \]

Each \ (x_i \) has a range limit:

\[\max(m - b_i, 0) \leq x_i \leq \min(a_i, m) \]

On the left is a fixed value, which we write as \ (S \); On the right is a stack of range summations. Do you feel better?

Note a property: if we record the sum of the minimum value of all \ (x_i \) as \ (L \) and the sum of the maximum value as \ (R \), then \ (L \leq \sum x_i \leq R \) and \ (\ sum x_i \) can fetch all \ ([L, R] \). This is junior high school inequality knowledge, good understanding.

This property transforms the problem into: we need to find the number closest to \ (\ lfloor \frac{S}{2} \rfloor \) in \ ([L, R] \).

At this time, this is a big problem: discuss the classification of \ (S, 2L, 2R \),

  • \(S \leq 2L \) directly minimize all values;
  • \(2R \leq S \) directly maximize all values;
  • \(S \in [2L, 2R] \), if \ (S \) is an even number, the answer is \ (0 \), otherwise it is \ (1 \) (because an odd number minus an even number cannot be an even number). At this time, the scheme can be directly greedy. First, take the minimum value of all \ (x \) and then greedily allocate \ (\ lfloor \frac{S}{2} \rfloor - L \), If the current maximum value can be taken, try to take the maximum value.
const int MAXN = 2e5 + 10;

int n, m;
std::pair<lli, lli> dishes[MAXN];
std::pair<lli, lli> bounds[MAXN];
lli chosenx[MAXN];

void _main() {
    n = read(); m = read();
    lli s = 0;
    lli suml = 0, sumr = 0;
    rep (i, 1, n) {
        lli a = read(); lli b = read();
        dishes[i] = {a, b};
        s += (a - b + m);
        bounds[i].fi = std::max(m - b, 0ll);
        bounds[i].se = std::min((lli) m, a);
        suml += bounds[i].fi; sumr += bounds[i].se;
    }
    if (2ll * sumr <= s) {
        printf("%lld\n", s - 2ll * sumr);
        rep (i, 1, n) {
            lli x = bounds[i].se, y = m - x;
            printf("%lld %lld\n", x, y);
        }
    }
    else if (s <= 2ll * suml) {
        printf("%lld\n", 2ll * suml - s);
        rep (i, 1, n) {
            lli x = bounds[i].fi, y = m - x;
            printf("%lld %lld\n", x, y);
        }
    }
    else {
        printf("%lld\n", (s % 2));
        lli ns = (s >> 1) - suml;
        rep (i, 1, n) {
            chosenx[i] = bounds[i].fi;
            lli dtx = bounds[i].se - bounds[i].fi;
            if (ns >= dtx) {
                ns -= dtx; chosenx[i] += dtx;
            } else {
                chosenx[i] += ns; ns = 0;
            }
        }
        lli checksum = 0;
        rep (i, 1, n) {
            printf("%lld %lld\n", chosenx[i], m - chosenx[i]);
            checksum += chosenx[i];
        }
        assert(std::abs(checksum * 2 - s) <= 1);
    }
}

int main() {
    // freopen("gout.out", "w", stdout);
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = read();
    while (T --> 0) {
        _main();
    }
    return 0;
}

H. Banquet Preparations 2

I still understand the meaning of the topic after reading the solution

But I didn't understand the solution.. Fill the pit again in a few days

Posted by morris on Wed, 03 Nov 2021 17:48:13 -0700