Problem
https://jzoj.net/senior/#main/show/6091
给定矩阵 A i , j = F ( i − 1 ) m + j A_{i,j}=F_{(i-1)m+j} Ai,j=F(i−1)m+j,对矩阵的子矩阵进行三种操作,左右倒置行,上下倒置列,矩阵倒置,每次操作的子矩阵必定包含上次操作的子矩阵,最后求 ∑ i = 1 n ∑ j = 1 m A i , j ∗ F ( i − 1 ) m + j \sum_{i=1}^n\sum_{j=1}^mA_{i,j}*F_{(i-1)m+j} i=1∑nj=1∑mAi,j∗F(i−1)m+j
n , m ≤ 4 ∗ 1 0 3 n,m\le 4*10^3 n,m≤4∗103
Solution
考虑把操作反过来做,那么每次对于多出来那一部分矩阵,实际上是进行了一个后缀的变换操作。
考虑到变换操作可以表示成一个线性变换,只与常数 k k k,坐标 ( x , y ) (x,y) (x,y)有关,维护这个常数 k k k,以及对应 a x + b y ax+by ax+by的系数,然后两个线性变换可以进行合并,于是就可以倒推一遍做到 O ( n m + q ) O(nm+q) O(nm+q)了。
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#define F(i,a,b) for (int i = a; i <= b; i ++)
#define get getchar()
const int N = 4 * 1e3 + 10, Q = 2e5 + 10, T = N * N;
using namespace std;
unsigned int Ans, f[T], A[N][N], B[N][N];
int Num, n,m,q, a,b, k1,k2, s1,s2, W,E, K1,K2, S1,S2, tmp;
int x1[Q], y1[Q], x2[Q], y2[Q], opt[Q]; bool bz[N][N];
struct node { int x, y; } TT[N][N];
void Re(int &x) {
char c = get; x = 0; int t = 1;
for (; !isdigit(c); c = get) t = (c == '-' ? - 1 : t);
for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = get); x *= t;
}
void Change(int &sx, int &sy) {
tmp = sx;
sx = K1 + (E == 1 ? sx : sy) * S1;
sy = K2 + (E == 1 ? sy : tmp) * S2;
}
void Doit(int x, int y) {
if (bz[x][y]) return; bz[x][y] = 1;
int xx = x, yy = y;
Change(xx, yy), TT[x][y] = {xx, yy};
}
int main() {
freopen("evernight.in","r",stdin);
freopen("evernight.out","w",stdout);
Re(Num), Re(n), Re(m), Re(q);
Re(a), Re(b), scanf("%u", &f[0]);
F(i, 1, n * m) f[i] = (a * f[i - 1] + b);
F(i, 1, q) Re(opt[i]), Re(x1[i]), Re(y1[i]), Re(x2[i]), Re(y2[i]);
F(i, 1, n) F(j, 1, m) A[i][j] = f[(i - 1) * m + j], TT[i][j] = {i, j};
S1 = S2 = E = s1 = s2 = W = 1;
for (int i = q, j; i; i = j - 1) {
for (j = i - 1; j && x1[j]==x1[i] && y1[j]==y1[i] && x2[j]==x2[i] && y2[j]==y2[i]; j --); j ++;
k1 = k2 = 0, s1 = s2 = W = 1;
F(k, j, i)
switch (opt[k]) {
case 1 : {
k2 = y1[k] + y2[k] - k2;
s2 = - s2;
break;
}
case 2 : {
k1 = x1[k] + x2[k] - k1;
s1 = - s1;
break;
}
case 3 : {
tmp = k1;
k1 = x1[k] - y1[k] + k2;
k2 = y1[k] - x1[k] + tmp;
W = 1 - W;
swap(s1, s2);
break;
}
}
if (!E)
swap(k1, k2), swap(s1, s2);
E = 1 - (E ^ W);
K1 += k1 * S1;
K2 += k2 * S2;
S1 = S1 * s1;
S2 = S2 * s2;
if (j - 1) {
F(y, y1[j], y2[j]) {
F(x, x1[j], x1[j - 1] - 1)
Doit(x, y);
F(x, x2[j - 1] + 1, x2[j])
Doit(x, y);
}
F(x, x1[j], x2[j]) {
F(y, y1[j], y1[j - 1] - 1)
Doit(x, y);
F(y, y2[j - 1] + 1, y2[j])
Doit(x, y);
}
}
else
F(x, x1[j], x2[j]) F(y, y1[j], y2[j])
Doit(x, y);
}
F(i, 1, n) F(j, 1, m) B[TT[i][j].x][TT[i][j].y] = A[i][j];
F(i, 1, n) F(j, 1, m)
Ans += B[i][j] * f[(i - 1) * m + j];
printf("%u", Ans);
}