摆放石子
题目描述
背景
有 n n n个盒子,第 i i i个盒子最多放 a i a_i ai个石子,当前盒子里的石子数为 b i b_i bi。两人轮流往盒子里放石子,且每一次放的数量不能超过当前盒子内的石子数,当有一方放不下石子时游戏结束且该方输,问先手是否能获胜
输入
- 第一行一个整数 T T T,表示有 T T T组数据;
- 对于每组数据,第一行一个整数 n n n;
- 接下来 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 1≤T≤50,1≤n≤50,0≤bi≤ai≤32767
题解
解法
可以看出,该题的规则描述的是一个有向图游戏的和,其中的每个有向图游戏
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=(a−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=a−1,则 S G = 1 SG = 1 SG=1,依此类推, S G = a − b SG = a - b SG=a−b
-
当 b = t b = t b=t时,必输,所以 S G = 0 SG = 0 SG=0
-
当 b < t b < t b<t时,设 t ′ = ( t − 1 ) > > 1 t^{'} = (t - 1) >> 1 t′=(t−1)>>1
- 若 b > t ′ b > t^{'} b>t′,则 2 b ≥ t 2b \ge t 2b≥t,当 b = t − 1 b = t - 1 b=t−1时, 2 b = 2 t − 2 2b = 2t - 2 2b=2t−2,所以 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,2t−2)})=mex({0,a−2t+2,⋯,a−t−1})=1,当 b = t − 2 b = t - 2 b=t−2时,同理可得 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,t−1),getSG(a,t),⋯,getSG(a,2t−4)})=mex({1,0,a−2t+4,⋯,a−t−1})=2,依此类推, S G = t − b SG = t - b SG=t−b
- 若 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({t−t′−1,⋯,t−2t′})=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)(c≤2t′−2<t),又由前两类得“若 t ′ ≤ b < t t^{'} \le b < t t′≤b<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
b≥t时可以直接得到
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;
}
打赏
制作不易,若有帮助,欢迎打赏!