关闭

51NOD 1661 黑板上的游戏(博弈 找规律)——算法马拉松17(告别奥运)

标签: 博弈SG运用马拉松
939人阅读 评论(0) 收藏 举报
分类:

传送门

1661 黑板上的游戏

Alice和Bob在黑板上玩一个游戏,黑板上写了n个正整数a1, a2, …, an,游戏的规则是

这样的:

1 . Alice占有先手主动权。

2 . 每个人可以选取一个大于1的数字擦去,并写上一个更小的数字,数字必须是整

数,然后由对方进行下一次操作。

3 . 如果擦去的数字是 x (x > 1) ,则写上的数字不能比 x/k 小,但是要比 x 小。这里的

除法为有理数除法。

4 . 不可以擦去任何一个数字 1 ,如果当前无法找到一个数字进行操作,则当前方输。

假设Alice和Bob都会选择最优的策略,请问Alice是否存在必胜的方案?

Input

第一行两个空格隔开的正整数n和k,其中n表示数字的个数,k表示游戏的参数。

第二行n个空格隔开的正整数,其中第i个表示ai。

1 ≤ n ≤ 10^5, 2 ≤ k ≤ 10^18, 1 ≤ ai ≤ 10^18。

Output

如果存在必胜方案,则输出“Alice i y”,其中i和y表示先手的一种能必胜的操作:将第i

个数修改为y。

如果没有,则输出“Bob”表示后手必胜。(输出不含引号)

Input示例

4 2

2 3 3 3

Output示例

Alice 2 2

解题思路:

官方题解(很详细):

固定 k 后对 sg(n) 进行打表,可以发现每个数字第一次出现的位置很有规律,即每隔

几个数字就出现一个已有的数字。删去每个数字的第一次出现位置之后,将剩下的数字

再排成一列,和原来的表是同构的,可以猜测 sg(n) 的递归解是

sg(1)=0,sg(ak+1)=sg(a),sg(ak+b)=a(k1)+b1(1<b<=k,b)

本题为 n 个游戏的和,所以对应的 sg 值为 sg(a1) xor sg(a2) xor ... xor sg(an)

如果 sg 值为 0,则后手必胜。

如果 sg 值不为 0,则先手必胜,必胜的操作是将下一轮游戏的 sg 值变为 0 ,设当前

sg 值为 m,则需要找到一组 iy 使得 m=sg(ai) xor sg(y)

sg(y)=m xor sg(aip=m xor sg(ai)q=(p1)/(k1)k+(p1) p=0q=1

可能的 y 只有q,qk+1,(qk+1)k+1,...其中小于 ai 的只有O(logk(ai))个,

在其中找一个不小于 ai/k 的即可,枚举 i,总能找到一个i对应的可行的 y

注意向上取整和判断整数溢出。

这里补一个简要证明,基于 sg 函数的定义,一个局面的 sg 值等于其后继局面的 sg

里没出现的最小非负整数,比如本题就是:
sg(n)=mex(sg(n1),sg(n2),...,sg((n1)/k+1))

其中 mex(S) 表示集合 S 中没有出现的最小非负整数,除法是下取整的整数除法。

考虑 nn1,它们所对应后继集合最多有两个元素不同,尝试利用数学归纳法来分

析,分析sg(n)时,假设已经得到sg(1),sg(2),...,sg(n1)满足上述结论。

由于后继局面可以写成一个区间的形式,所以下面的分析用 [L,R] 来简化表示

(sg(L),sg(L+1),...,sg(R))

n=ak+1时,ak+1对应的后继是[a+1,ak]ak对应的后继是 [a,ak1]

假设 sg(ak+1)sg(a),则sg(ak+1)<sg(a),这是因为 a 不是ak+1的后

继,如果 sg(a) 不是最小没出现的,那么最小没出现的只能是更小的数。

由于 sg(ak+1) 是一个比 sg(a) 小的数,说明 [a+1,ak] 里没有这个数,那么

[a,ak1] 里更不会有这个数,因此 sg(ak)<=sg(ak+1),从而sg(ak)<sg(a)

但是 sg(ak) 根据归纳假设是 [1,ak] 里最大的值,因此有 sg(a)<=sg(ak),与上

述产生矛盾,所以sg(ak+1)=sg(a)

n=ak+b(1<b<=k) 时,n 对应的后继是 [a+1,n1]n1 对应的

后继是[a+1,n2]

由上述可以知道 sg(n1)<sg(n) ,这是因为 sg(n1) 没有在 n1 的后继里

出现,所以 sg(n) 只会变大不会变小。

如果 b=2 ,那么 sg(n1)=sg(a) ,则 n 的后继相当于[a,ak],根据归纳假设

这里面的值都是在 0sg(ak) 之间的,因此sg(n)=sg(n2)+1

如果b>2,那么同理可得sg(n)=sg(n1)+1

然后找一下具体的式子即可,有了具体的式子就方便找逆映射了。

需要注意很多的细节问题。。。
My Code

/**
2016 - 08 - 29 下午
Author: ITAK

Motto:

今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1e18+5;
const int MAXN = 1e6+5;
const LL MOD = 1e9+7;
const double eps = 1e-7;
const double PI = acos(-1);
using namespace std;
LL Scan_LL()///输入外挂
{
    LL res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
int Scan_Int()///输入外挂
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
void Out(LL a)///输出外挂
{
    if(a>9)
        Out(a/10);
    putchar(a%10+'0');
}
LL a[MAXN], sg[MAXN];
int main()
{
    int n;
    LL k;
    while(~scanf("%d%lld",&n,&k))
    {
        LL ans = 0, tmp, ret, x;
        int j = -1;
        memset(a, 0, sizeof(a));
        for(int i=1; i<=n; i++)
        {
            x = Scan_LL();
            a[i] = x;
            if(x == 1)
                continue;
            tmp = x;
            LL tp1 = x/k;
            LL tp2 = x%k;
            while(tmp)
            {
                if(tp2 == 0)
                {
                    tp1--;
                    tp2 = k;
                    sg[i] = (tp1*(k-1)+tp2-1);
                    ///cout<<"a["<<i<<"] ="<<a[i]<<endl;
                    ans ^= sg[i];
                    break;
                }
                else if(tp2 > 1)
                {
                    sg[i] = (tp1*(k-1)+tp2-1);
                    ans ^= sg[i];
                    break;
                }
                else
                {
                    tmp = (tmp-1)/k;
                    tp1 = tmp/k;
                    tp2 = tmp%k;
                }
            }
        }
        if(ans)
        {
            tmp = ans;
            for(int i=1; i<=n; i++)
            {
                if(a[i] == 1)
                    continue;
                LL p = (tmp ^ sg[i]);
                LL q = (p-1)/(k-1)*k+(p-1)%(k-1)+2;
                if(p == 0)
                    q = 1;
                ret = q;
                while(1)
                {
                    if(ret>=a[i] || ret<0)
                        break;
                    LL tp = a[i]/k;
                    if(a[i] % k)
                        tp++;
                    if(ret >= tp)
                    {
                        j = i;
                        goto endW;
                    }
                    ret = ret*k+1;
                }
            }
            endW:;
            printf("Alice %d %lld\n",j, ret);
        }
        else
            puts("Bob");
    }
    return 0;
}
0
0
查看评论

51nod 1661 黑板上的游戏(博弈sg函数找规律)

1661 黑板上的游戏 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 Alice和Bob在黑板上玩一个游戏,黑板上写了n个正整数a1, a2, …, an,游戏的规则是这样的: 1. Alice占有先手主动权。 2. 每个人可以选取一个大于...
  • Miracle_ma
  • Miracle_ma
  • 2016-08-29 13:39
  • 609

51nod 1824(算法马拉松30)

51nod 1824(算法马拉松30)嘻嘻嘻。感觉还是有进步的。再接再厉。显然:f(t)=∑x+y=trxby(tx)f(t)=\sum_{x+y=t}r_xb_y\binom{t}{x}组合解释就是确定其中一种颜色即可。显然。直接FFTFFT不可行。但是。在mod 2mod\ 2意义下。...
  • ZLH_HHHH
  • ZLH_HHHH
  • 2017-10-29 21:15
  • 245

51nod算法马拉松31总结

听说这场F的出题人是栋栋
  • alan_cty
  • alan_cty
  • 2017-11-27 20:46
  • 295

51Nod 算法马拉松23

A : 打表找规律 B : 数学期望 C : 拓扑排序+DP D : 状压DP E : 莫队+树状数组+卡常数 F : Unfinished听说省选推迟了一个月,整个人都不好了。放假打了一场51Nod,感觉整个人更不好了。A 1718 “多项式”能出在第一题的多项式肯定是有奇技淫巧的,打表...
  • ziqian2000
  • ziqian2000
  • 2017-04-03 00:04
  • 798

51nod - 1661 黑板上的游戏 - 博弈论

题目:51nod 算法马拉松 17(告别奥运)A 黑板的游戏 题意:两个人轮流玩擦数字游戏,给定n个数ai(i=1,2,3,...,n)和一个k,(1≤n≤105,2≤k≤1018,1≤ai≤1018)n个数 {a_i(i=1,2,3,...,n)}和一个k,(1\le n\le 10^{5}, ...
  • qq_23323877
  • qq_23323877
  • 2016-08-31 15:05
  • 288

51nod 算法马拉松32 题解

A 特殊表示法 题意:给出两个用斐波那契数来表示的数,输出它们和的斐波那契表示。n 题解:把两个数对应位相加后,不停地暴力扫,每次暴力进位,直到扫到不能进位且没有2为止。 #include #include #include #include #include using namespace...
  • qq_33229466
  • qq_33229466
  • 2018-01-02 16:47
  • 346

51Nod 算法马拉松24

A : 构造 B : 状压DP C : 构造 D : 线段树或平衡树 E : 树链剖分+线段树 F : UnfinishedA 1804 小C的多边形强行猜了一个结论,试了一下小数据发现没问题,那就假装没问题吧……就是外面一圈1~n-1,里面把1插在n-2和n-1之间,其他的顺次递推。本题...
  • ziqian2000
  • ziqian2000
  • 2017-05-01 01:04
  • 882

51nod算法马拉松20总结

好吧这也称不上是一个总结 只不过旷掉了一场思想上AK的模拟赛过来淦题而已 结果发现好像比上次要难的样子?(还是我变弱了?) 实力原因不会做的题就不写了 题目链接 A: 考虑每一条边对答案贡献 也就是这条边所连接的两个联通块中都至少有一个点被选择的方案数。 设其中一个联通块的大小为si...
  • alan_cty
  • alan_cty
  • 2016-11-30 19:32
  • 538

51NOD 1537 分解(矩阵快速幂)——算法马拉松17(告别奥运)

传送门问 (1+2√)n(1+\sqrt 2) ^n 能否分解成 m−−√+(√m−1)\sqrt m +\sqrt(m-1)的形式 如果可以 输出 m MOD (109+7)m\ MOD\ (10^9+7) 否则 输出 nonoInput一行,一个数 nn。 (n<=...
  • qingshui23
  • qingshui23
  • 2016-08-29 09:59
  • 772

51nod算法马拉松18总结

第一次打算法马拉松。 第一个晚上后就有人ak实在把我吓了一跳,后来十多个人ak了,几乎想要放弃的感觉。。。A: 构造题,首先可以证明n为偶数时是无解的。 然后我在n为奇数的构造上花了点时间,后来观察n=5时的答案发现构造方法如下: 枚举i,然后给所有边(i,j)(i < j)按顺序染色...
  • WorldWide_D
  • WorldWide_D
  • 2016-09-26 15:01
  • 1131
    个人资料
    • 访问:528945次
    • 积分:11552
    • 等级:
    • 排名:第1588名
    • 原创:639篇
    • 转载:5篇
    • 译文:0篇
    • 评论:93条
    博客专栏