「Fortuna OJ」Aug 5th – Group A 解题报告

A – 矩阵游戏

这道题看了题解之后发现就是一道 sb 题。

考虑将每一列看成一个数,发现如果忽略掉列的操作,这些数仍然满足等差的条件,所以我们只要暴力算完第一列就可以进行等差了。如果考虑列的操作,那么我们就大力暴力就行了,时间复杂度是\(O(n + m)\)。

// A.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e6 + 200, mod = 1e9 + 7;

int row[MAX_N], col[MAX_N], n, m, k;
long long ans = 0;
char opt[20];

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= max(n, m); i++)
        row[i] = col[i] = 1;

    while (k--)
    {
        int x, y;
        scanf("%s%d%d", opt + 1, &x, &y);
        if (opt[1] == 'R')
            row[x] = 1LL * row[x] * y % mod;
        else
            col[x] = 1LL * col[x] * y % mod;
    }
    int colBatch = 0, batch = 0;
    for (int i = 1; i <= n; i++)
        colBatch = (1LL * colBatch + 1LL * (1LL * (i - 1) * m % mod + 1) % mod * row[i] % mod) % mod, batch = (1LL * batch + 1LL * row[i]) % mod;
    int current = colBatch;
    for (int j = 1; j <= m; j++)
        ans = (ans + 1LL * current * col[j] % mod) % mod, current = (1LL * current + 1LL * batch) % mod;
    printf("%lld", ans);
    return 0;
}

B – 跳房子

这道题听毒瘤的,很长。

我们考虑设置数组\(jump[i]\)表示从第\(i\)行第一列跳到下一次第一列的行号。这样的话,我们在找循环节的时候可以快很多,只需要除掉就好,剩余的地方进行暴力就行。

修改就用到了比较玄秘的方法,考虑一个点被修改对第一列的影响,发现被影响的点必然在一个区间内,且连续,所以我们可以从被修改点往左跳,找到区间并且全部修改为新的答案,这样就可以不用被计算多次了。

// B.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 2020;

int jump[MAX_N], ptx, pty;
int mp[MAX_N][MAX_N], n, m, q;
char opt[20];

int fix(int pa, int pb) { return (pa % pb + pb) % pb; }

int next_row(int x, int y)
{
    int next_row = -1;
    int max_value = -1;
    for (int rr = x - 1; rr <= x + 1; ++rr)
    {
        const int value = mp[fix(rr, n)][fix(y + 1, m)];
        if (value > max_value)
        {
            max_value = value;
            next_row = rr;
        }
    }
    return next_row;
}

int rush(int x, int y)
{
    do
    {
        x = fix(next_row(x, y++), n);
    } while (y < m);
    return x;
}

struct interval
{
    int l = std::numeric_limits<int>::max();
    int r = std::numeric_limits<int>::min();
    bool isCotain(int x) { return l <= x && x <= r; }
    bool isEmpty() { return l > r; }
    int size() { return r - l + 1; }
};

void update(int x, int y)
{
    const int target_row = rush(x, y);
    interval rows;
    rows.l = rows.r = x;
    int cc = y;
    while (cc > 0)
    {
        --cc;
        interval new_rows;
        for (int rr = rows.l - 1; rr <= rows.l + 1; ++rr)
        {
            if (rows.isCotain(next_row(rr, cc)))
            {
                new_rows.l = rr;
                break;
            }
        }
        for (int rr = rows.r + 1; rr >= rows.r - 1; --rr)
        {
            if (rows.isCotain(next_row(rr, cc)))
            {
                new_rows.r = rr;
                break;
            }
        }
        if (new_rows.isEmpty())
            return;
        rows = new_rows;
    }
    if (rows.size() >= n)
        for (int rr = 0; rr < n; ++rr)
            jump[rr] = target_row;
    else
        for (int rr = rows.l; rr <= rows.r; ++rr)
            jump[fix(rr, n)] = target_row;
    return;
}

void move(int steps)
{
    static int walk_id = 0;
    static int last_walk_id[MAX_N];
    static int last_k[MAX_N];
    walk_id++;

    if (steps >= m - pty)
    {
        steps -= (m - pty);
        ptx = rush(ptx, pty), pty = 0;
    }
    while (steps >= m)
    {
        steps -= m;
        ptx = jump[ptx];

        if (last_walk_id[ptx] == walk_id)
        {
            const int cycle_len = last_k[ptx] - steps;
            if (steps >= cycle_len)
            {
                const int n_cycles = steps / cycle_len;
                steps -= n_cycles * cycle_len;
            }
        }
        last_walk_id[ptx] = walk_id;
        last_k[ptx] = steps;
    }
    while (steps--)
        ptx = fix(next_row(ptx, pty++), n);
}

int main()
{
    /*
    freopen("jump.in", "r", stdin);
    freopen("jump.out", "w", stdout);
    */
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            scanf("%d", &mp[i][j]);
    scanf("%d", &q);
    for (int i = 0; i < n; i++)
        jump[i] = rush(i, 0);
    while (q--)
    {
        int a, b, c;
        scanf("%s%d", opt + 1, &a);
        if (opt[1] == 'm')
            move(a), printf("%d %d\n", ptx + 1, pty + 1);
        else
        {
            scanf("%d%d", &b, &c);
            a--, b--;
            mp[a][b] = c;
            for (int i = a - 1; i <= a + 1; i++)
                update(fix(i, n), fix(b - 1, m));
        }
    }
    return 0;
}

C – 优美序列

这道题暴力跳,然后 AC 看天命。

// C.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200;

int n, arr[MAX_N], pos[MAX_N], q, log2_[MAX_N];
int stmax[18][MAX_N], stmin[18][MAX_N], posmax[18][MAX_N], posmin[18][MAX_N];

inline int query_pos_max(int l, int r)
{
    int len = r - l + 1, k = log2_[len];
    return max(posmax[k][l], posmax[k][l + len - (1 << k)]);
}

inline int query_pos_min(int l, int r)
{
    int len = r - l + 1, k = log2_[len];
    return min(posmin[k][l], posmin[k][l + len - (1 << k)]);
}

inline int query_max(int l, int r)
{
    int len = r - l + 1, k = log2_[len];
    return max(stmax[k][l], stmax[k][l + len - (1 << k)]);
}

inline int query_min(int l, int r)
{
    int len = r - l + 1, k = log2_[len];
    return min(stmin[k][l], stmin[k][l + len - (1 << k)]);
}

int main()
{

    freopen("sequence23.in", "r", stdin);
    freopen("sequence.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 2; i <= n; i++)
        log2_[i] = log2_[i >> 1] + 1;
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &arr[i]), pos[arr[i]] = i;
        stmax[0][i] = arr[i], stmin[0][i] = arr[i];
        posmin[0][arr[i]] = i, posmax[0][arr[i]] = i;
    }
    for (int i = 1; (1 << i) <= n; ++i)
        for (int j = 1; j <= n; ++j)
        {
            stmax[i][j] = max(stmax[i - 1][j], stmax[i - 1][j + (1 << (i - 1))]);
            stmin[i][j] = min(stmin[i - 1][j], stmin[i - 1][j + (1 << (i - 1))]);
            posmax[i][j] = max(posmax[i - 1][j], posmax[i - 1][j + (1 << (i - 1))]);
            posmin[i][j] = min(posmin[i - 1][j], posmin[i - 1][j + (1 << (i - 1))]);
        }
    scanf("%d", &q);
    while (q--)
    {
        int l, r;
        scanf("%d%d", &l, &r);
        int mx, mi;
        while (r - l + 1 != (mx = query_max(l, r)) - (mi = query_min(l, r)) + 1)
        {
            l = min(l, query_pos_min(mi, mx));
            r = max(l, query_pos_max(mi, mx));
        }
        printf("%d %d\n", l, r);
    }
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *