zoukankan      html  css  js  c++  java
  • ZOJ3084_S-Nim

    题目的意思是这样的,给定你若干堆石子,每次你可以从任一堆取出某些固定数量的石子,每次取完后必须保证没堆石子的数量不为0,谁无法操作了就算fail。

    刚刚开始看题目的时候有点也没有思路,甚至连Sg函数也没有听过。后来学习了一番,说说自己的想法吧。

    _________________有关SG函数的由来,性质及其我个人对sg函数的了解见下一篇日志。

    这个题目可以这样考虑,由于每次可取的数字是一个给定的集合,我们可以求出所有的数所对应的sg的函数值(我用的是dp,不过好像跟多人喜欢用记忆化搜)。

    由于博弈论里面的许多奇奇怪怪的定理,最终我们只要求出每一堆的石子数所对应的sg值的总共异或值ans,如果ans不等于0,那么说明先手有必胜的策略,否则后手有必胜的策略。

    另外说明一下,sg函数值对应的是在当前状态能转化到的所有后继状态sg值中的第一个没有出现的非负整数。很神奇吧。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define maxn 10005
     5 using namespace std;
     6 
     7 bool vis[105];
     8 int a[105],sg[maxn],n,m,k,ans;
     9 
    10 void getSG()
    11 {
    12     for (int i=0; i<maxn; i++)
    13     {
    14         memset(vis,false,sizeof vis);
    15         for (int j=1; j<=n && a[j]<=i; j++) vis[sg[i-a[j]]]=true;
    16         for (int j=0; ; j++)
    17             if (!vis[j])
    18             {
    19                 sg[i]=j;
    20                 break;
    21             }
    22     }
    23 }
    24 
    25 int main()
    26 {
    27     while (scanf("%d",&n) && n)
    28     {
    29         for (int i=1; i<=n; i++) scanf("%d",&a[i]);
    30         sort(a+1,a+1+n);
    31         getSG();
    32         scanf("%d",&m);
    33         while (m--)
    34         {
    35             scanf("%d",&n);
    36             ans=0;
    37             while (n--) scanf("%d",&k),ans^=sg[k];
    38             if (ans) printf("W");
    39                 else printf("L");
    40         }
    41         printf("
    ");
    42     }
    43 
    44     return 0;
    45 }
    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    2018CodeM复赛
    poj3683
    bzoj3991
    bzoj2809
    bzoj1001
    bzoj1412
    计蒜之道2018复赛
    HDU2255
    bzoj1010
    bzoj2006
  • 原文地址:https://www.cnblogs.com/lochan/p/3372983.html
Copyright © 2011-2022 走看看