BZOJ 3901 棋盘游戏 解题报告
这题有个重要性质:
我们设 Flag[i][j] 表示 (i, j) 是否被奇数个操作所覆盖,
也就是操作次数对 2 取模。
设 x = (n + 1) / 2。
那么对于所有的合法的操作方案,
令 1 <= i <= x , 1 <= j < x,
都有 Flag[i][j] ^ Flag[i][x] ^ Flag[i][j + x] = 0
令 1 <= i < x , 1 <= j <= x,
都有 Flag[i][j] ^ Flag[x][j] ^ Flag[i + x][j] = 0
考虑任意一次操作,如果覆盖了 (i, x),
那么在 (i, j) 和 (i, j + x) 中必然有且仅有一个被覆盖。
(i, j) 和 (i + x, j) 同理,
于是每次都会改变那个三元组中的两个元素,或者一个都不改变。
所以这个性质也是成立的。
那么怎么说明满足上述性质的 Flag[][] 就可以对应一个合法的方案呢?
我们考虑:
我们无论怎样在这个满足性质的 Flag[][] 基础上进行操作,
这个 Flag[][] 还会是满足性质的。
先不考虑其他格子的 Flag[][] 值,
我们考虑所有的 1 <= i <= x,1 <= j <= x:
我们都可以把 Flag[i][j] 变成 0。
然后我们考虑对于所有的 1 <= i <= x,x < j <= n:
Flag[i][j] = Flag[i][x] ^ Flag[i][j - x] = 0 ^ 0 = 0
同理,其他格子的 Flag[][] 值也都会是 0。
于是满足上述性质的 Flag[][] 就可以对应一个合法的方案。
好了,那么我们就暴力枚举 Flag[x][1] - Flag[x][x] 的值,
然后 Flag[x][x + 1] - Flag[x][n] 的值也就可以确定了,
其次再分别枚举 Flag[1][x] - Flag[x - 1][x] 的值,
(这里是指一个一个处理这些值,不用再 dfs 了)
那么 Flag[x + 1][x] - Flag[n][x] 的值也可以确定了。
在此基础上对于 1 < i < x,1 < j < x:
我们可以枚举 Flag[i][j] 的值,
那么 Flag[i + x][j], Flag[i][j + x], Flag[i + x][j + x] 的值都可以确定,
于是取最优值即可。
复杂度 O(1.4^n * n^2)。
毕竟 Gromah 太弱,只会做水题。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 #define N 33 + 5 8 #define INF 0x7fffffff 9 10 int n, x, Max, A[N][N]; 11 bool Flag[N][N]; 12 13 inline int get(int u) 14 { 15 return u == 1 ? -1 : 1; 16 } 17 18 inline int Calc() 19 { 20 for (int i = x + 1; i <= n; i ++) 21 Flag[i][x] = Flag[x][x] ^ Flag[i - x][x]; 22 int res = 0; 23 for (int i = 1; i <= n; i ++) 24 res += get(Flag[i][x]) * A[i][x]; 25 for (int i = 1; i < x; i ++) 26 { 27 int _Max = -INF, sum; 28 for (int k = 0; k < 2; k ++) 29 { 30 Flag[x][i] = k; 31 Flag[x][i + x] = Flag[x][i] ^ Flag[x][x]; 32 sum = get(Flag[x][i]) * A[x][i] + get(Flag[x][i + x]) * A[x][i + x]; 33 for (int j = 1; j < x; j ++) 34 { 35 int _res = -INF; 36 for (int _k = 0; _k < 2; _k ++) 37 { 38 Flag[j][i] = _k; 39 Flag[j][i + x] = Flag[j][i] ^ Flag[j][x]; 40 Flag[j + x][i] = Flag[j][i] ^ Flag[x][i]; 41 Flag[j + x][i + x] = Flag[j + x][i] ^ Flag[j + x][x]; 42 int _sum = get(Flag[j][i]) * A[j][i] + get(Flag[j][i + x]) * A[j][i + x]; 43 _sum += get(Flag[j + x][i]) * A[j + x][i] + get(Flag[j + x][i + x]) * A[j + x][i + x]; 44 _res = max(_res, _sum); 45 } 46 sum += _res; 47 } 48 _Max = max(_Max, sum); 49 } 50 res += _Max; 51 } 52 return res; 53 } 54 55 inline void dfs(int z) 56 { 57 if (z > x) 58 { 59 Max = max(Max, Calc()); 60 return ; 61 } 62 Flag[z][x] = 0; 63 dfs(z + 1); 64 Flag[z][x] = 1; 65 dfs(z + 1); 66 } 67 68 int main() 69 { 70 #ifndef ONLINE_JUDGE 71 freopen("3901.in", "r", stdin); 72 freopen("3901.out", "w", stdout); 73 #endif 74 75 scanf("%d", &n); 76 x = n + 1 >> 1; 77 for (int i = 1; i <= n; i ++) 78 for (int j = 1; j <= n; j ++) 79 scanf("%d", A[i] + j); 80 dfs(1); 81 printf("%d\n", Max); 82 83 #ifndef ONLINE_JUDGE 84 fclose(stdin); 85 fclose(stdout); 86 #endif 87 return 0; 88 }