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
", Max);
82     
83     #ifndef ONLINE_JUDGE
84         fclose(stdin);
85         fclose(stdout);
86     #endif
87     return 0;
88 }
原文地址:https://www.cnblogs.com/gromah/p/4420489.html