sg函数的一些题

来源:互联网 发布:怎样成为网络歌手软件 编辑:程序博客网 时间:2024/06/06 02:52

模板1如下(SG打表):

//f[]:可以取走的石子个数  //sg[]:0~n的SG函数值  //hash[]:mex{}  int f[K],sg[N],hash[N];  void getSG(int n)  {          memset(sg,0,sizeof(sg));          for(int i=1; i<=n; i++) {                  memset(hash,0,sizeof(hash));                  for(int j=0; f[j]<=i && j < k; j++) //k是f[]的有效长度                          hash[sg[i-f[j]]]=1;                  for(int j=0; ; j++) {   //求mes{}中未出现的最小的非负整数                          if(hash[j]==0) {                                  sg[i]=j;                                  break;                          }                  }          }  }  

模板2如下(dfs):

//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍  //n是集合s的大小 S[i]是定义的特殊取法规则的数组  int s[N],sg[N],n;  int getSG(int x)  {          if(sg[x]!=-1)                  return sg[x];          bool vis[M];          memset(vis,0,sizeof(vis));          for(int i=0; i<n; i++) {                  if(x>=s[i])                          vis[getSG(x-s[i])]=1;          }          for(i=0;; i++)                  if(!vis[i]) {                          sg[x]=i;                          break;                  }          return sg[x];  }  

例一: hdu 1536 S-Nim

题意:首先输入K 表示一个集合的大小 之后输入集合 表示对于这对石子只能去这个集合中的元素的个数

之后输入 一个m 表示接下来对于这个集合要进行m次询问

之后m行 每行输入一个n 表示有n个堆 每堆有n1个石子 问这一行所表示的状态是赢还是输 如果赢输入W否则L

思路:对于n堆石子 可以分成n个游戏 之后把n个游戏合起来就好了

代码:

#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;typedef long long LL;const int MAXN = 108;int a[MAXN*MAXN], pre[MAXN], k;void init() {    int f[MAXN];    for(int i = 1; i <= 10000; i++) {        a[i] = 0;        memset(f, 0, sizeof(f));        for(int j = 1; j <= k && pre[j] <= i; j++)            f[a[i-pre[j]]] = 1;        for(int j = 0; ; j++)            if (!f[j]) {                a[i] = j;                break;            }    }}int main() {    int  m;    //freopen("in.txt", "r", stdin);    while (scanf("%d", &k) && k) {        for(int i = 1; i <= k; i++)            scanf("%d", pre+i);        sort(pre+1, pre+k+1);        init();        scanf("%d", &m);        while (m--) {            int n;            scanf("%d", &n);            int res = 0;            for(int i = 1; i <= n; i++) {                int t;                scanf("%d", &t);                res ^= a[t];            }            if (res) printf("W");            else printf("L");        }        puts("");    }    return 0;}

例二:
Gym - 101128GGame of Cards

题意:有n堆扑克牌,两个人轮流玩游戏,游戏规则:

先选一堆扑克牌,然后拿走堆顶0-k张,剩余的堆顶那一张牌上是几就必须再拿走几张,当某一方无牌可拿或者剩余张数不够必须拿走的张数时则该方输

代码:

#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;typedef long long LL;const int MAXN = 1008;int a[MAXN], k, val[MAXN];void init() {    int f[22];    for(int i = 1; i <= 1000; i++) {        a[i] = 0;        memset(f, 0, sizeof(f));        for(int j = 0; j <= k; j++)        if (i-j-val[i-j] >= 0)//这里注意一下就好了;            f[a[i-j-val[i-j]]] = 1;        for(int j = 0; ; j++)            if (!f[j]) {                a[i] = j;                break;            }    }}int main() {    int m;    //freopen("in.txt", "r", stdin);    scanf("%d%d", &m, &k);    val[0] = 1;    int res = 0;    while (m--) {        int n;        scanf("%d", &n);        for(int i = 1; i <= n; i++)            scanf("%d", val+i);        init();        res ^= a[n];    }    if (res) printf("Alice can win.\n");    else printf("Bob will win.\n");    return 0;}


sg函数巧用

hdu 1729  Stone Game

1、设当前的箱子容量为si,求出一个t满足:t + t * t < si,如果当前箱子里有ci颗石头,

1、ci > t 则必胜;

2、ci == t 则必败;

3、ci < t不能确定,将t作为si递归调用函数。

当满足ci > t时,return si - ci 作为当前状态的sg值。因为:

如图:

当ci在si点时,为有向图的端点,出度为0,也就是必败点,所以sg值为0;

当ci 位于si - 1时,ci的端点可能的sg值构成的集合为{0},所以当前sg值 为1;

当ci 位于si - 2 时,ci的端点可能的sg值构成的集合为{0, 1},所以当前的sg值为2;

可得,ci所在位置的sg值为si - ci;

代码:

//#include<bits/stdc++.h>#include <iostream>#include <string>#include <queue>#include <map>#include <cstring>#include <cstdio>#include <cmath>using namespace std;typedef long long LL;const int MAXN = 1000008;int sg(int c, int s) {    int q = sqrt(s);    while (q*(q+1) >= s) q--;    if (c > q) return s-c;    else return sg(c, q);//和暴力不一样有点小灵活}int main() {    int n, p = 1;    while (scanf("%d", &n) && n) {        printf("Case %d:\n", p++);        int res = 0;        while (n--) {            int s, c;            scanf("%d%d", &s, &c);            res ^= sg(c, s);        }        if (res) puts("Yes");        else puts("No");    }    return 0;}

sg 水水的;

hdu 1730 Northcott Game

要理解sg函数啊

代码:

//#include<bits/stdc++.h>#include <iostream>#include <string>#include <queue>#include <map>#include <cstring>#include <cstdio>#include <cmath>using namespace std;typedef long long LL;const int MAXN = 1000008;int main() {    int n, m;    while (~scanf("%d%d", &n, &m)) {        int res = 0;        while (n--) {            int s, c;            scanf("%d%d", &s, &c);            res ^= int(abs(s-c)-1);        }        if (res) puts("I WIN!");        else puts("BAD LUCK!");    }    return 0;}


hdu 2524 A Chess Game

题意:给一些点和有向边,组成一个有向无环图(不止一个头结点,因为这个wa一次.....);在一些点上放一些棋子,2个人进行游戏,每次进行的操作是根据有向边来移动一个棋子;直到没有棋子移动,那个人就输了;

题解:明显的sg函数

代码:

//#include<bits/stdc++.h>#include <iostream>#include <string>#include <queue>#include <map>#include <cstring>#include <cstdio>#include <cmath>#include <vector>using namespace std;typedef long long LL;const int MAXN = 1008;int sg[MAXN], adjList[MAXN][MAXN], adjN[MAXN];int n;int dfs(int k) {    int num[MAXN] = {0};    if (sg[k]) return sg[k];    for(int i = 0; i < adjN[k]; i++) {        num[dfs(adjList[k][i])] = 1;    }    for(int i = 0; ; i++)        if (!num[i]) return sg[k] = i;}int main() {    //freopen("in.txt", "r", stdin);    while (~scanf("%d", &n)) {        memset(sg, 0, sizeof(sg));        for(int i = 0; i < n; i++) {            scanf("%d", adjN+i);            for(int j = 0; j < adjN[i]; j++) {                scanf("%d", &adjList[i][j]);            }        }        for(int i = 0; i < n; i++)            dfs(i);        int m;        while(scanf("%d", &m) && m) {            int res = 0;            while(m--) {                int t;                scanf("%d", &t);                res ^= sg[t];            }            if (res) puts("WIN");            else puts("LOSE");        }    }    return 0;}


原创粉丝点击