AtCoder Regular Contest 153

B - Grid Rotations

https://atcoder.jp/contests/arc153/tasks/arc153_b

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 500 points

Problem Statement

We have a grid with H rows from top to bottom and W columns from left and right. Initially, the square at the i-th row from the top and j-th column from the left has a lowercase English letter Ai,j.

Let us perform Q operations on this grid. In the i-th operation, we are given integers ai and bi such that 1aiH1 and 1biW1, and do the following.

  • Let R1, R2, R3, and R4 be rectangular regions within the grid defined as follows:

    • R1 is the intersection of the top ai rows and leftmost bi columns;
    • R2 is the intersection of the top a_i rows and rightmost Wbi columns;
    • R3 is the intersection of the bottom H-a_i rows and leftmost bi columns;
    • R4 is the intersection of the bottom H-a_i rows and rightmost Wbi columns.
  • Rotate 180 degrees each of R1, R2, R3, and R4.
    Here, a 180-degree rotation of a rectangular region R within the grid moves the character on the square at the i-th from the top and j-th column from the left in R to the square at the i-th from the bottom and j-th column from the right in R. See also the figures for the samples.

Print the grid after all Q operations.

Constraints

  • 2H,W, and HW5×105.
  • Ai,j is a lowercase English letter.
  • 1Q2×105
  • 1aiH1
  • 1biW1

Input

The input is given from Standard Input in the following format:

H W
A1,1A1,W

AH,1AH,W
Q
a1 b1

aQ bQ

Output

Print the grid after the operations in the following format, where Bi,j is the character on the square (i,j) on the final grid.

B1,1B1,W

BH,1BH,W

Sample Input 1

4 5
abcde
fghij
klmno
pqrst
1
3 3

Sample Output 1

mlkon
hgfji
cbaed
rqpts

The grid will change as follows.

Sample Input 2

3 7
atcoder
regular
contest
2
1 1
2 5

Sample Output 2

testcon
oderatc
ularreg

The grid will change as follows.

Sample Input 3

2 2
ac
wa
3
1 1
1 1
1 1

Sample Output 3

ac
wa

The grid will change as follows.

题解

同一行/列元素操作后仍在同一行/列

通过观察可以发现,题目所述操作是对整行、整列进行的。因此同一行元素操作后仍在同一行、同一列元素操作后仍在同一列,只是顺序变化了。

由此,我们可以想到,无需维护每次操作整个矩阵的值,而只用维护行列前后对应关系即可,即第 x 行/列操作后变成了第 y 行/列。最后输出时根据行列对应关系生成新矩阵即可。

如果使用暴力法,时间复杂度为:O(Q(H+W)). 根据题目要求,最坏的情况是 H=W700,复杂度 108 级别,会超时。由此可见,必须对行列对应关系的维护方式进行优化。

行列对应关系的特点

我们通过一个例子来解释,我们先只考虑行,因为这个问题行列是独立的:

:123456784:432187652:345678127:187654323:78123456

此时获取还看不出规律,我们加上一些辅助:

:12345678|4:4321|87652:345678|127:1|87654323:78|123456

这样就很明显了,每次操作其实序列都是顺序的,只不过起始点发生了偏移。并且奇数次操作时为逆序,偶数次操作时为顺序。那么我们就不需要维护整个行列对应关系了,而只需要维护起始点 1 就行了。最后输出时,通过起始点的位置,结合操作的次数,生成出行列对应关系,再用行列对应关系生成出新矩阵就行了。

时间复杂度为:O(Q+HW),可以满足题目要求。

代码

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int H, W;
    cin >> H >> W;
    vector<string> A(H);
    for (int i = 0; i < H; i++)
        cin >> A[i];
    int Q;
    cin >> Q;
    int start_row = 0, start_col = 0;
    for (int i = 0; i < Q; i++)
    {
        int a, b;
        cin >> a >> b;
        a--, b--;
        start_row = (start_row <= a) ? (a - start_row) : (H - start_row + a);
        start_col = (start_col <= b) ? (b - start_col) : (W - start_col + b);
    }
    vector<int> row(H), col(W);
    if (Q & 1)
    {
        for (int i = 0; i < H; i++)
            row[(start_row - i + H) % H] = i;
        for (int i = 0; i < W; i++)
            col[(start_col - i + W) % W] = i;
    }
    else
    {
        for (int i = 0; i < H; i++)
            row[(start_row + i) % H] = i;
        for (int i = 0; i < W; i++)
            col[(start_col + i) % W] = i;
    }
    for (int i = 0; i < H; i++)
    {
        for (int j = 0; j < W; j++)
            cout << A[row[i]][col[j]];
        cout << endl;
    }
    return 0;
}