zoukankan      html  css  js  c++  java
  • [ZJOI2009]染色游戏

    Description

    一共n × m 个硬币,摆成n × m 的长方形。dongdong 和xixi 玩一个游戏, 每次可以选择一个连通块,并把其中的硬币全部翻转,但是需要满足存在一个 硬币属于这个连通块并且所有其他硬币都在它的左上方(可以正左方也可以正 上方),并且这个硬币是从反面向上翻成正面向上。dongdong 和xixi 轮流操作。 如果某一方无法操作,那么他(她) 就输了。dongdong 先进行第一步操作,假 设双方都采用最优策略。问dongdong 是否有必胜策略。

    Input

    第一行一个数T,表示他们一共玩T 局游戏。接下来是T 组游戏描述。每 组游戏第一行两个数n;m,接下来n 行每行m 个字符,第i 行第j 个字符如 果是“H” 表示第i 行第j 列的硬币是正面向上,否则是反面向上。第i 行j 列 的左上方是指行不超过i 并且列不超过j 的区域。

    Output

    对于每局游戏,输出一行。如果dongdong 存在必胜策略则输出“- -”(不含 引号) 否则输出“= =”(不含引号)。(注意输出的都是半角符号,即三个符号 ASCII 码分别为45,61,95)

    Sample Input

    32
    3
    HHH
    HHH
    2 3
    HHH
    TTH
    2 1
    T
    H

    Sample Output

    = =
    - -
    - -

    HINT

    对于40% 的数据,满足1 ≤ n;m ≤ 5。
    对于100% 的数据,满足1 ≤ n;m ≤ 100,1 ≤ T ≤ 50。

    先考虑一维

    SG[i]为单独考虑只有i是反面,其他都是正面的SG值,这样原情况可以转化为很多子游戏

    假设要求SG[3]

    也就是001

    有这么几种:000  010  110

    SG[3]=mex{0,2,2^1}=1

    SG(4) = mex{0, 1, 1 XOR 2, 1 XOR 2 XOR 1} = 4;


    SG(5) = mex(0, 4, 4 XOR 1, 4 XOR 1 XOR 2, 4 XOR 1 XOR 2 XOR 1) = 1;

    枚举了很多SG发现SG[n]=lowbit(n)

    将类似的方法拓展到2维:

    要求SG[2][2],也就是

    归纳得出,在i,j都大于1时,SG[i][j]=2i+j-2

    在i或j为0时,为一维的算法

    优于2200过大,所以用二进制存储

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 struct Num
     8 {
     9   int a[201];
    10 }SG[101][101],ans;
    11 int n,m,flag;
    12 char s[102];
    13 Num operator ^(const Num &A,const Num &B)
    14 {int i;
    15   Num C;
    16   memset(C.a,0,sizeof(C.a));
    17   for (i=0;i<=200;i++)
    18     if (A.a[i]!=B.a[i]) C.a[i]=1;
    19   return C;
    20 }
    21 int lowbit(int x)
    22 {
    23   return x&(-x);
    24 }
    25 void getSG()
    26 {int i,j;
    27   SG[1][1].a[0]=1;
    28   for (i=2;i<=100;i++)
    29     {
    30       int x=lowbit(i);
    31       for (j=0;j<=7;j++)
    32     if ((1<<j)==x)
    33       SG[1][i].a[j]=SG[i][1].a[j]=1;
    34     }
    35   for (i=2;i<=100;i++)
    36     {
    37       for (j=2;j<=100;j++)
    38     {
    39       SG[i][j].a[i+j-2]=1;
    40     }
    41     }
    42 }
    43 int main()
    44 {int T,i,j;
    45   cin>>T;
    46   getSG();
    47   while (T--)
    48     {
    49       cin>>n>>m;
    50       memset(ans.a,0,sizeof(ans.a));
    51       for (i=1;i<=n;i++)
    52     {
    53       scanf("%s",s+1);
    54       for (j=1;j<=m;j++)
    55         {
    56           if (s[j]=='T') ans=ans^SG[i][j];
    57         }
    58     }
    59       flag=0;
    60       for (i=0;i<=100;i++)
    61     if (ans.a[i])
    62       {flag=1;break;}
    63       if (flag) printf("-_-
    ");
    64       else printf("=_=
    ");
    65     }
    66 }
  • 相关阅读:
    洛谷 P1886 滑动窗口 (单调队列)
    Acwing 288.休息时间 (环形DP)
    Acwing 287.积蓄程度 (树形DP换根)
    2020 Multi-University Training Contest 5 Tree (树形DP)
    剑指offer-JZ50-数组中的重复数字(C++)
    假设以下有一个结构体存放的是学生的记录,每条记录包括:学号、姓名、成绩
    剑指offer-JZ48-不用加减乘除做加法(C++)
    剑指offer-JZ51-构建乘积数组
    数据结构与算法->递归
    力扣(LeetCode)试题6-Z字形变换 C++代码
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8397463.html
Copyright © 2011-2022 走看看