Loading [MathJax]/extensions/tex2jax.js

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

A – 矩阵游戏

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
// 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; }
// 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\)行第一列跳到下一次第一列的行号。这样的话,我们在找循环节的时候可以快很多,只需要除掉就好,剩余的地方进行暴力就行。

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
// 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; }
// 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 看天命。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}
// 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; }
// 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 *