• HDU1536 S-Nim


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1536

    题目大意:给出k个可取数的集合,m个查询。查询每次是否是先后获胜。

    定义一些名词

    后继:如果当前状态为x,采取一个合法的操作后,状态变为y,那么y是x的后继(2是5的后继,<取3个>)

    mex:最小不在集合中的整数

    SG(x) = mex{ SG(y) | y是x的后继}

    例如 :每次可以取1,3,4个

    sg[0] = 0;

    sg[1] = mex(sg[0]) = {0} = 1;

    sg[2] = mex(sg[1]) = {1} = 0;

    sg[3] = mex(sg[0], sg[2]) = {0, 0} = 1;

    sg[4] = mex(sg[3], sg[1], sg[0]) = {0, 1, 1} = 2;

    sg[5] = mex(sg[4], sg[2], sg[1]) = {1, 0, 2} = 3;

    SG函数打表的两个方法:

    ①AC代码:

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <stdlib.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <sstream>
    #include <stack>
    using namespace std;
    #define FO freopen("in.txt", "r", stdin);
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const int maxn = 10010;
    
    int sg[maxn], s[maxn],k;//sg函数值 s是可取的数(1,3,4) 
    bool vis[maxn];//标记 
    
    void SG(int n) {
    	memset(sg, 0, sizeof(sg));
    	for(int i = 1; i < maxn; i++) {
    		memset(vis, false, sizeof(vis));
    		for(int j = 0; j < n && s[j] <= i; j++)//s[j] <= i 表示后继     j < n 共有n种取法 
    			vis[sg[i-s[j]]] = true;//把后继的sg值标记,出现过了 
    		for(int j = 0; j <= maxn; j++) {
    			if(!vis[j]) {//第一个没有出现的数字   sort优化 
    				sg[i] = j;
    				break;
    			}
    		}
    	}
    } 
    
    
    int main() {
    	//FO;
    	int m, l, x;
    	while(~scanf("%d", &k)&&k) {
    		for(int i = 0; i < k; i++)
    			scanf("%d", &s[i]);
    		sort(s, s+k);
    		SG(k);
    		scanf("%d", &m);
    		while(m--) {
    			scanf("%d", &l);
    			int sum = 0;
    			while(l--) {
    				scanf("%d", &x); 
    				sum ^= sg[x];//每一堆的异或和 
    			}
    			if(sum == 0)//必败 P 
    				printf("L");
    			else// 必胜 N 
    				printf("W");
    		}
    		printf("
    ");
    	}
    } 
    
    

    ②:AC代码:

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <stdlib.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <sstream>
    #include <stack>
    using namespace std;
    #define FO freopen("in.txt", "r", stdin);
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    
    int sg[10010], s[110],k;//意义同上 
    int sG(int x) {
    	if(sg[x] != -1) //已经计算过直接返回 
    		return sg[x];
    	bool vis[110];
    	memset(vis, 0, sizeof(vis));//标记 
    	for(int i = 0; i < k; i++) {//跑可取数 
    		if(x >= s[i]) {//如果是后继 
    			sG(x-s[i]);//递归得到后继的sg值 
    			vis[sg[x-s[i]]] = 1;//把后继的sg值标记出现过 
    		}
    	}
    	int e;
    	for(int i = 0;;i++) {//第一个没有出现的 
    		if(!vis[i]) {
    			e = i;
    			break;
    		}
    	}
    	return sg[x] = e;//返回值 
    }
    
    
    int main() {
    	//FO;
    	int m, l, x;
    	while(~scanf("%d", &k)&&k) { 
    		for(int i = 0; i < k; i++)
    			scanf("%d", &s[i]);
    		memset(sg, -1, sizeof(sg));//初始化-1 
    		sort(s, s+k);//排序 
    		scanf("%d", &m);
    		while(m--) {
    			scanf("%d", &l);
    			int sum = 0;
    			while(l--) {
    				scanf("%d", &x);
    				sum ^= sG(x);
    			}
    			if(sum == 0)
    				printf("L");
    			else
    				printf("W");
    		}
    		printf("
    ");
    	}
    } 
    
  • 相关阅读:
    关于float与double
    【编程实践】母牛生小牛
    wlan的QOS配置
    C语言itoa函数和atoi 函数
    类似于QQ的简单的聊天代码
    多线程吃饺子练习
    线程练习
    接口练习
    电视练习
    5.22
  • 原文地址:https://www.cnblogs.com/ACMerszl/p/9572949.html
Copyright © 2020-2023  润新知