【hdu1536】【poj2960】S-Nim

题意

题意就是给出一个数组h,为每次可以取石子的数目。

然后给你n堆石子每堆si。求解先手能不能赢?

分析

根据\(h\)数组预处理出\(sg[i]\)表示\(i\)个石子对应的\(sg\)值。

然后\(sg[s_1]\otimes sg[s_2]\otimes ...\otimes sg[s_n]\)即可。

小结

SG函数的使用,通常是ICG模型上不只存在一个石子。

如果只存在一个,可以简化SG函数,直接用布尔值代替。这样的普适性虽然没这么高,但是可以降低运算复杂度。

【hdu1848】Fibonacci again and again

题意

题意:取石子问题,一共有3堆石子,每次只能取斐波那契数个石子,先取完石子者胜利,问先手胜还是后手胜

\(n,m,p\leq 1000\)

分析

预处理斐波那契数。

求sg值。

【hdu1847】Good Luck in CET-4 Everybody!

题意

1、 总共n张牌;

2、 双方轮流抓牌;

3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)

4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;

分析1

计算SG函数。

    sg[0]=0;
    rep(i,1,U_N) {
        for (int j=1;j<=i;j<<=1)
            mrk[sg[i-j]]=i;
        rep(j,0,i+1)
            if (mrk[j]!=i) {
                sg[i]=j;
                break;
            }
    }

分析2

其实分析1过于复杂了。

根本不用求出SG函数的值,因为我们只有单一的石子在移动。

我们只用算出SG值对应的布尔值即可。

    rep(i,1,U_N) {
        for (int j=1;j<=i;j<<=1)
            if (!sg[i-j]) {
                sg[i]=1;
                break;
            }
    }

分析3

分析2的方法可以进行记忆化搜索。

这就是所谓的对抗搜索。

分析4

由于涉及到了2的幂,这看似有进一步的规律可循。

直接打表,进一步的找SG函数的规律,化简运算复杂度。

发现呈现110110110110......的规律。

直接OK了。

    while (~scanf("%d",&n)) {
        if (n%3!=0)
            printf("Kiki\n");
        else printf("Cici\n");
    }

小结

(1)博弈问题的思路:

①找规律

②对抗搜索 or 递推

③SG函数

从上到下由简到繁。

(2)注意SG的值的上下界。

SG的取值或许有一个较小的上界。

SG的取值总长均摊下来或许比想象中优。

对于一般的情况,有\(sg[i]<i的度数\)

对于线性的情况,必定有\(sg[i]<i\)

【hdu3032】Nim or not Nim?

题意

每一轮从两种操作中做一种:

①取走任意个石子

②分成两堆

\(每堆石子数\leq 10^9\)

分析

首先求出\(sg\)。

\(sg[n]=mex(sg[0],sg[1],...,sg[n-1],sg[0]\otimes sg[n],sg[1]\otimes sg[n-1],sg[2]\otimes sg[n-2],...,sg[n]\otimes sg[0])\)

直接求解\(O(n^2)\),不行,所以必然找规律化简。

发现:

int SG(int x) {
    if (x%4==1) return x;
    else if (x%4==2) return x;
    else if (x%4==3) return x+1;
    else if (x%4==0) return x-1;
}

核心代码

int cas;
int n;
int xorSum;

int SG(int x) {
    if (x%4==1) return x;
    else if (x%4==2) return x;
    else if (x%4==3) return x+1;
    else if (x%4==0) return x-1;
}

int main(void) {
    #ifndef ONLINE_JUDGE
    freopen("xsy1159.in","r",stdin);
    freopen("xsy1159.out","w",stdout);
    #endif

    cas=rd();
    rep(tms,1,cas) {
        n=rd(); xorSum=0;
        rep(i,1,n) xorSum^=SG(rd());
        if (xorSum>0) printf("Alice\n"); else printf("Bob\n");
    }

    return 0;
} 

小结

(1)做这道题的时候第一次错了,因为暴力求SG写错了。

所以这启示我不论什么程序都要好好写,就算没有好好写都要检查一遍。

(2)一个状态的集合也可以当做一个单点的SG。

【xsy1159】【gzoi2015】石子游戏

题意

Alice 和 Bob 总喜欢聚在一起玩游戏(T­_T),今天他(她)们玩的是一款新型的取石子游戏。游戏一开始有 N 堆石子,Alice 和 Bob 轮流取出石子。在每次操作中,游戏者必须选择其中的一堆石子,并作出下列的其中一种操作:

(1)移去整堆石子

(2)假设石子堆中有 X 颗石子,取出 Y 颗石子,其中 1≤Y<X ,且 gcd(X,Y)=1

游戏结束的条件是:取出最后一颗石子的人胜出。众所周知,Alice和Bob都是绝顶聪明的,假设他们在游戏中都采取最优的策略,问最后谁会胜出游戏呢?

\(T,N\leq 100\)

\(石子个数\leq 10^6\)

分析

【定义1】

若\(n=1\),则\(s_n=1\)

若\(n>1\),则\(s_n=mex_{1\leq i\leq n且(i,n)=1}(s_i)\)

【定义2】

函数\(r\)是\(Z\)到\(Z\)的一个映射,即\(r:Z\rightarrow Z\),\(r(n)\)表示比\(n\)小的素数个数。

例如:\(r(2)=1,r(3)=2,r(5)=3\)

【定义3】

\(m(n)\):\(n\)的最小正因子

例如:\(m(2)=2,m(15)=3,m(16)=2,m(56)=7\)

【定理1(\(s_n\)的封闭形式)】

对于任意整数\(n\),\(n>1\),\(s_n=s_{m(n)}=r(m(n))+1\)

证明:(1)当\(n=1\)时,\(r(m(n))=r(1)+1=1\),\(s_1=1\)

\(\therefore s_1=r(m(1))+1\)

(2)假设当\(n<k\)时都成立,求证当\(n=k\)时亦成立

①当\(k\)为素数时,

\(s_k=mex(s_1,s_2,...,s_{k-1})=r(k)+1\)

②当\(k\)为合数时,

要证:\(s_k=r(m(k))+1\Leftrightarrow mex_{1\leq i<k且(i,k)=1}(s_i)=r(m(k))+1\)

即证:满足以下两个条件

A. \(\forall x\in[1,r(m(k))],\exists i\in[1,k)且(i,k)=1,s.t.s_i=x\)

B. \(\not\exists i\in [1,k)且(i,k)=1,s.t.s_i=r(m(k))+1\)

条件A证明:取1和比\(m(k)\)小的素数即可一一构造出来

条件B证明:\(s_i=r(m(i))+1=r(m(k))+1\)

即要使得\(m(i)=m(k)\)

而\(i\)与\(k\)互质,所以一定不存在。

综上,对于任意整数\(n\),\(n>1\),\(s_n=s_{m(n)}=r(m(n))+1\)

证毕!

上面摆了整个证明的过程。

那么,思考的过程应该是怎么样的?怎么才能推出这样的答案呢?

首先,最基本的,我列出了\(s\)的\(O(n\log n)\)递推一位的关系式。

接下来,需要考虑的就是怎么优化了,即怎么找规律。

嗯,由于这道题涉及了gcd,所以规律应该会和素数、质因数分解一类的有些关系,就让我写个暴力的程序,先找找素数的规律。

发现了\(s_k=r(k)+1\)。

那么,对于合数,又有怎样的规律呢?

由于数据范围比较大,我想到了线性筛,所以要在线性筛的过程中求解sg函数吗。

所以应该会和最小质因子有关系,发现和最小质因子的值直接相同了!

规律寻找完毕!!

小结

那么,这道题目给了我怎么的启发呢?

像这样一道题,它明显地摆着是要找规律了。那我就先根据一些特性猜测一下规律,写个程序或者手算小数据看看。

核心代码

void init(void)
{
    sg[1]=v[1]=used[1]=1,tt=2;
    for (int i=2;i<M;i++)
    {
        if (!v[i])
        {
            p[++p[0]]=i;
            sg[i]=p[0]+1;
            for (;used[tt];tt++);
            pre[p[0]]=tt;
        }
        for (int j=1;j<=p[0];j++)
        {
            if (i*p[j]>=M) break;
            v[i*p[j]]=1,sg[i*p[j]]=pre[j];
            if (i%p[j]==0) break;
        }
        used[sg[i]]++;
    }
}

SG函数 专题练习的更多相关文章

  1. 【UVA10561】Treblecross(SG函数)

    题意:有n个格子排成一行,其中一些格子里面有字符X.两个游戏者轮流操作,每次可以选一个空格,在里面放上字符X. 如果此时有3个连续的X出现,则该游戏者赢得比赛.初始条件下不会有3个X连续出现. 判断先 ...

  2. 博弈论 | 详解搞定组合博弈问题的SG函数

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天这篇是算法与数据结构专题的第27篇文章,我们继续深入博弈论问题.今天我们要介绍博弈论当中非常重要的一个定理和函数,通过它我们可以解决许多 ...

  3. HDU 5795 A Simple Nim 打表求SG函数的规律

    A Simple Nim Problem Description   Two players take turns picking candies from n heaps,the player wh ...

  4. 【转】博弈—SG函数

    转自:http://chensmiles.blog.163.com/blog/static/12146399120104644141326/ http://blog.csdn.net/xiaofeng ...

  5. HDU 1848 Fibonacci again and again【SG函数】

    对于Nim博弈,任何奇异局势(a,b,c)都有a^b^c=0. 延伸: 任何奇异局势(a1, a2,… an)都满足 a1^a2^…^an=0 首先定义mex(minimal excludant)运算 ...

  6. POJ2425 A Chess Game[博弈论 SG函数]

    A Chess Game Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 3917   Accepted: 1596 Desc ...

  7. bzoj1188 [HNOI2007]分裂游戏 博弈论 sg函数的应用

    1188: [HNOI2007]分裂游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 973  Solved: 599[Submit][Status ...

  8. BZOJ1188 [HNOI2007]分裂游戏(SG函数)

    传送门 拿到这道题就知道是典型的博弈论,但是却不知道怎么设计它的SG函数.看了解析一类组合游戏这篇论文之后才知道这道题应该怎么做. 这道题需要奇特的模型转换.即把每一个石子当做一堆石子,且原来在第i堆 ...

  9. sg函数与博弈论2

    参考链接: http://blog.sina.com.cn/s/blog_51cea4040100h3l9.html 这篇主要就是讲anti-sg.multi-sg和every-sg的. 例1 poj ...

随机推荐

  1. Linux modules install

    安装模块的时候出现错误:modprobe: chdir(3.0.35-g6774ed9-dirty): No such file or directory. 内核模块没有安装正确.本文记录解决方法. ...

  2. zabbix调用微信报警

    1.注册微信企业号,可以选团体号(针对小团队) 2.创建管理组 3.创建部门,记住部门id (使用了部门id,发消息会发送到所有部门成员,所以如果要单独发送给某个用户,""这样设置 ...

  3. Line segment matching

    FMII2方法:FMII方法的轻微的修改.有限线段和无限线段(直线)的匹配. 求解方法: SVD分解 Unit Quaternion 协方差矩阵: 通过对C进行SVD分解得到R,根据R求得T. 算法流 ...

  4. EF CodeFirst增删改查之‘CRUD’

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精    本篇旨在学习EF增删改查四大操作 上一节讲述了EF ...

  5. erlang note

    没有关于erlang interface ,继续寻找吧... --------------------------------------------------------------- erl - ...

  6. js 给样式添加随机颜色

    下面提供了三种获取随机颜色值的方法 方法一: 创建一个颜色 HEX 值数组,然后随机抽取这个数组里6个值,组合生成颜色. function color1(){ var color = "&q ...

  7. 微软 .net 你更新这么快IDE vs2015 、语法糖 6.0、framework、‘吹得这么牛,然并用

    好久没写吐槽文章了,因为无尽的加班,也因为工作的变迁,又因为最近看了微软又尼玛发布什么什么,好受不了. 今年大专毕业第八个年头了,人也到了30,真是光阴荏苒啊.最近这一两年发生了很多事,让我自己倍受打 ...

  8. Linux入门:运行级别解析

    Linux入门:运行级别解析   一.查看当前运行级别 Ubuntu中,runlevel命令 可以查看当前运行级别: CentOS中,who -r 命令查看当前运行级别:   www.2cto.com ...

  9. ASP.NET MVC 3 CheckBoxList 的使用

    在以前的 ASP.NET MVC 中可以直接使用 CheckBoxList,但后来不知道什么原因在 MVC 中移除了 CheckBoxList,所以默认情况下 ASP.NET MVC 3 中是没有 C ...

  10. Ninject简介

    1.为什么要用Ninject? Ninject是一个IOC容器用来解决程序中组件的耦合问题,它的目的在于做到最少配置.其他的的IOC工具过于依赖配置文件,需要使用assembly-qualified名 ...