出处不详 摆放石子

摆放石子

题目描述

背景

n n n个盒子,第 i i i个盒子最多放 a i a_i ai个石子,当前盒子里的石子数为 b i b_i bi。两人轮流往盒子里放石子,且每一次放的数量不能超过当前盒子内的石子数,当有一方放不下石子时游戏结束且该方输,问先手是否能获胜

输入

  1. 第一行一个整数 T T T,表示有 T T T组数据;
  2. 对于每组数据,第一行一个整数 n n n
  3. 接下来 n n n行,每行两个整数 a i , b i a_i , b_i ai,bi

输出

对于每组数据,输出一行 Y e s Yes Yes N o No No,表示先手是否能获胜

数据范围

1 ≤ T ≤ 50 , 1 ≤ n ≤ 50 , 0 ≤ b i ≤ a i ≤ 32767 1 \le T \le 50 , 1 \le n \le 50 , 0 \le b_i \le a_i \le 32767 1T50,1n50,0biai32767

题解

解法

可以看出,该题的规则描述的是一个有向图游戏的和,其中的每个有向图游戏 G i G_i Gi为:一个能容纳 a i a_i ai个石子的盒子,已经被放入了 b i b_i bi个石子后,两人轮流放石子,每次放的石子数不能超过已有的石子数,直到放不了石子的一方输
接下来需计算出所有 S G ( G i ) SG(G_i) SG(Gi),定义一个函数 g e t S G ( a , b ) getSG(a , b) getSG(a,b)用来求容量 a a a、已放入 b b b的游戏的 S G SG SG函数值,函数中定义变量 t t t表示满足 t + t < a t + t < a t+t<a的最大整数,即 t = ( a − 1 ) > > 1 t = (a - 1) >> 1 t=(a1)>>1

  1. b > t b > t b>t时,若 b = a b = a b=a,则 S G = 0 SG = 0 SG=0,所以若 b = a − 1 b = a - 1 b=a1,则 S G = 1 SG = 1 SG=1,依此类推, S G = a − b SG = a - b SG=ab

  2. b = t b = t b=t时,必输,所以 S G = 0 SG = 0 SG=0

  3. b < t b < t b<t时,设 t ′ = ( t − 1 ) > > 1 t^{'} = (t - 1) >> 1 t=(t1)>>1

    • b > t ′ b > t^{'} b>t,则 2 b ≥ t 2b \ge t 2bt,当 b = t − 1 b = t - 1 b=t1时, 2 b = 2 t − 2 2b = 2t - 2 2b=2t2,所以 S G = m e x ( { g e t S G ( a , t ) , g e t S G ( a , t + 1 ) , ⋯   , g e t S G ( a , 2 t − 2 ) } ) = m e x ( { 0 , a − 2 t + 2 , ⋯   , a − t − 1 } ) = 1 SG = mex(\{ getSG(a , t) , getSG(a , t + 1) , \cdots , getSG(a , 2t - 2) \}) = mex(\{ 0 , a - 2t + 2 , \cdots , a - t - 1 \}) = 1 SG=mex({getSG(a,t),getSG(a,t+1),,getSG(a,2t2)})=mex({0,a2t+2,,at1})=1,当 b = t − 2 b = t - 2 b=t2时,同理可得 S G = m e x ( { g e t S G ( a , t − 1 ) , g e t S G ( a , t ) , ⋯   , g e t S G ( a , 2 t − 4 ) } ) = m e x ( { 1 , 0 , a − 2 t + 4 , ⋯   , a − t − 1 } ) = 2 SG = mex(\{ getSG(a , t - 1) , getSG(a , t) , \cdots , getSG(a , 2t - 4) \}) = mex(\{ 1 , 0 , a - 2t + 4 , \cdots , a - t - 1 \}) = 2 SG=mex({getSG(a,t1),getSG(a,t),,getSG(a,2t4)})=mex({1,0,a2t+4,,at1})=2,依此类推, S G = t − b SG = t - b SG=tb
    • b = t ′ b = t^{'} b=t S G = m e x ( { g e t S G ( a , t ′ + 1 ) , ⋯   , g e t S G ( a , 2 t ′ ) } ) = m e x ( { t − t ′ − 1 , ⋯   , t − 2 t ′ } ) = 0 SG = mex(\{ getSG(a , t^{'} + 1) , \cdots , getSG(a , 2t^{'}) \}) = mex(\{ t - t^{'} - 1 , \cdots , t - 2t^{'} \}) = 0 SG=mex({getSG(a,t+1),,getSG(a,2t)})=mex({tt1,,t2t})=0
    • b < t ′ b < t^{'} b<t,则 2 b < t 2b < t 2b<t,所以只有可能用到 g e t S G ( a , c ) ( c ≤ 2 t ′ − 2 < t ) getSG(a , c)(c \le 2t^{'} - 2 < t) getSG(a,c)(c2t2<t),又由前两类得“若 t ′ ≤ b < t t^{'} \le b < t tb<t,则 g e t S G ( a , b ) = g e t S G ( t , b ) getSG(a , b) = getSG(t , b) getSG(a,b)=getSG(t,b)”,所以此时可以将 a a a换成 t t t,求 g e t S G ( t , b ) ( b < t ′ ) getSG(t , b)(b < t^{'}) getSG(t,b)(b<t)即可

    综上, S G = g e t S G ( t , b ) SG = getSG(t , b) SG=getSG(t,b)

所以当 b ≥ t b \ge t bt时可以直接得到 S G SG SG,反之则需将 a a a换成 t t t代入递归求解
代码如下:

#include<cstdio>

#define il inline

il int read() {
    int x = 0;
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x;
}

il int getSG(int a, int b) {
    int t = (a - 1) >> 1; 
    if(b > t) return a - b;
    if(b == t) return 0;
    return getSG(t, b);
}

int main() {
    int t = read();
    while(t--) {
        int ans = 0, n = read();
        while(n--) {
            int a = read(), b = read();
            if(a && b && a != b) ans ^= getSG(a, b);     //a = 0、b = 0或a = b时SG = 0,而ans ^ 0 = 0
        }
        ans ? puts("Yes") : puts("No");
    }
    return 0;
}

打赏

制作不易,若有帮助,欢迎打赏!
赞赏码

支付宝付款码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒蜩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值