zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    增强MyEclipse提示功能
    Mysql安装配置,修改初试密码。
    在我的电脑里面创建图标
    popup non topmost
    多线程下载或上传数据限速
    SynchronizationContext
    linux运维笔记——常用命令详解diff
    linux运维笔记——curl
    linux下mysql的源码安装
    shell编程——变量的数值计算
  • 原文地址:https://www.cnblogs.com/gromah/p/4420489.html
Copyright © 2011-2022 走看看