10404 - Bachet's Game

来源:互联网 发布:自动采集网站php源码 编辑:程序博客网 时间:2024/05/08 22:22

题目链接

题意:由一堆石子, 给出石子的总数n~1e6, 接下来由stan和ollie两个人玩游戏,给出m, 在给出m~10种取石子的方法(即为每次可取走石子的数量),由stan先,两人轮流取走石子,最后一个将石子全部去完的人胜利,问, 给出的一堆石子, 两人均按最好的方案游戏, 最后将会是谁胜 ?

题解:本来是一个标准的sg函数的题目,1e6*10也能过。sg【0】,之后sg【i】枚举i取一次可得到j的sg【j】,集合搞出来后找出从0开始的第一个没有的数作为sg【i】,sg是0的先手必败。这道题目也可以dp来写,枚举m次选择,必败与必胜状态的改变。

重点:法一sg函数,集合的统计,这里利用了have=i的标号。法二,必胜和必败状态的改变。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxn = 1e6 + 10;int dp[maxn], a[20], n, tot;void getDp()//dp思想{    dp[0] = 0;    for(int i = 1;i <= tot;i++)    {        int flag = 0;        for(int j = 1;j <= n;j++)//出现必败就为必胜        {            if(i >= a[j]&&(dp[i-a[j]]==0))            {                flag = 1;                break;            }        }        dp[i] = flag;    }}int sg[maxn];int have[maxn];void getSg(){    CLR(have);//清空    sg[0] = 0;    for(int i = 1;i <= tot;i++)    {        for(int j = 1;j <= n;j++)        {            if(i >= a[j])            {                have[sg[i-a[j]]] = i;//标记成i            }        }        for(int j = 0;;j++)        {            if(have[j]!=i)            {                sg[i] = j;                break;            }        }    }    //printf("%d\n", sg[1]);}void solve(){    getSg();//用的sg打表,最后跟0比较    int t = sg[tot];    if(t!=0)    {        printf("Stan wins\n");    }    else    {        printf("Ollie wins\n");    }}int main(){    //freopen("5Ein.txt", "r", stdin);    //freopen("5Eout.txt", "w", stdout);    while(scanf("%d%d", &tot, &n) != EOF)    {        REP_D(i, 1, n)        {            scanf("%d", &a[i]);        }        solve();    }    return 0;}


0 0
原创粉丝点击