取石子

题解

在笔者写这篇题解之前,你可以发现,网上大部分流行的解法都是 O ( n ∑ a ) O\left(n\sum a\right) O(n∑a)的,但我们可以发现在 LOJ 的较快代码都是清一色的线性时间复杂度。
这篇题解将主要对这种线性的做法进行讲解。

首先我们抬出我们的结论:
我们记 x = ∑ [ a i = 1 ] x=\sum [a_i=1] x=∑[ai​=1]即 1 1 1堆的个数, y = ∑ [ a i > 1 ] ( a i + 1 ) − 1 y=\sum [a_i>1](a_i+1)-1 y=∑[ai​>1](ai​+1)−1,也就是非 1 1 1堆的和。
当 y ⩽ 2 y\leqslant 2 y⩽2时,如果 3 ∣ x 3|x 3∣x,后手必胜,否则先手必胜。
当 y > 2 y>2 y>2时,如果 2 ∣ x ∧ 2 ∣ y 2|x\wedge2|y 2∣x∧2∣y,后手必胜,否则先手必胜。

显然,不是 1 1 1的堆是不会对我们的答案产生影响的,它一定会做到最终被减到 0 0 0并且完全合(即自身合并的次数一定被用光)。
事实上,它不可能被任何一个人减到 0 0 0,如果有人妄图将它减到 0 0 0,浪费它的合并次数,那么当他将它从 2 2 2变到 1 1 1,是另一个人就会处于干扰对手的意愿,将其合并到它大于 1 1 1的朋友上,这也可以说明我们 y y y中最后要减去一个没处合并的 1 1 1。

显然,如果 y ⩽ 2 y\leqslant 2 y⩽2,那么我们的序列必然是数个连续的 1 1 1,最后可能跟一个 2 2 2。
如果我们的 3 ∣ x 3|x 3∣x,也就是说我们的 1 1 1的个数是 3 3 3的倍数。
如果我们的先手将一个 1 1 1变为 0 0 0,在有 2 2 2的情况下,后手可以将 2 2 2变成 1 1 1,在没 2 2 2的情况下,后手可以将两个 1 1 1变成 2 2 2。
如果先手将一个 2 2 2变成 1 1 1,后手将这个 1 1 1变成 0 0 0即可。
如果先手合并了两个 1 1 1,得到一个 2 2 2,那么在没 2 2 2的情况下,我们可以将一个 1 1 1消去,保持在原状态。
在有 2 2 2的情况,我们考虑现在 x x x的奇偶性没变, y y y的奇偶性变了,显然现在 2 ∤ y 2\not | y 2​∣y,因为现在它们多了一个可合并项,在 y > 2 y>2 y>2的情况看来,我们的后手现在是胜态。
于是,我们的目的有转到了证明 y > 2 y>2 y>2部分的结论是否成立,不妨先假设 y > 2 y>2 y>2部分的结论时对的,在下面会进行证明,先将 y ⩽ 2 y\leqslant 2 y⩽2的情况说明完。
如果我们的 3 ∤ x 3\not | x 3​∣x,那么显然我们的先手可以将现在的情况变为 3 ∣ x 3|x 3∣x,此时他是后手,可以胜利。
如果 x % 3 = 1 x\%3=1 x%3=1,直接将这个 1 1 1减掉即可。
如果 x % 3 = 2 x\%3=2 x%3=2,在有 2 2 2的情况下,可以将 2 2 2变成 1 1 1,没 2 2 2的情况下,将这两个 1 1 1合成 2 2 2。
于是我们便达到了 3 ∣ x 3|x 3∣x的情况,原来的先手现在成了后手,必将胜利。

对于 y > 2 y>2 y>2的情况,我们先说明 2 ∣ x ∧ 2 ∣ y 2|x\wedge 2|y 2∣x∧2∣y的情况后手是必胜的。
如果先手消一个 1 1 1,后手跟着消 1 1 1即可。
如果先手使 y y y减 1 1 1,如果现在 y > 3 y>3 y>3,后手让 y y y减 1 1 1即可。否则,如果前面有 1 1 1的话,一定是偶数个,我们合并两个 1 1 1,可以使 y y y变成 6 6 6。不然的话,整个序列中就一个 3 3 3,此时将这个 3 3 3变成 2 2 2,一个 2 2 2明显是后手必胜。
如果先手将一个 1 1 1合并到 2 2 2上,后手跟着合并一个 1 1 1即可。
如果先手将两个 1 1 1合成 2 2 2,此时 y y y会增加 3 3 3,后手使 y y y减 1 1 1即可。
这样,无论如何,我们的后手都有能与先手匹敌的方案。
如果 2 ∤ x ∨ 2 ∤ y 2\not |x\vee 2\not |y 2​∣x∨2​∣y,先手是一定有一种方案使其变成 2 ∣ x ∧ 2 ∣ y 2|x\wedge 2|y 2∣x∧2∣y的,此时作为后手的原来的先手胜利。
如果 2 ∤ x ∧ 2 ∣ y 2\not | x\wedge 2|y 2​∣x∧2∣y,先手可以直接消去一个 1 1 1。
如果 2 ∣ x ∧ 2 ∤ y 2| x\wedge 2\not |y 2∣x∧2​∣y,当 y > 3 y>3 y>3时,先手可以将 y y y减去一个 1 1 1,当 y = 3 y=3 y=3时,先手如果前面有 1 1 1就合并连个 1 1 1,否则将 y y y减 1 1 1。
如果 2 ∤ x ∧ 2 ∤ y 2\not |x\wedge 2\not | y 2​∣x∧2​∣y,先手可以将一个 1 1 1合并到 2 2 2上面去。
于是,无论如何先手都能赢了。
这样,我们就证罢了 y > 2 y>2 y>2的情况了,那么 y ⩽ 2 y\leqslant 2 y⩽2的情况也就证明完毕了。

于是,我们直接记录 1 1 1的个数与非 1 1 1的数的总和就可以线性求出答案了。
时间复杂度 O ( n ) O\left(n\right) O(n)。

源码

这还要看吗。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 50055
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
typedef long double ld;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=233333333;
const int zero=100;
const int lim=200;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int T,n,a[MAXN],sum,num;
signed main(){read(T);while(T--){read(n);num=sum=0;for(int i=1;i<=n;i++){read(a[i]);if(a[i]>1)sum+=a[i]+1;else num++;}if(sum)sum--;if((sum<3&&num%3)||(sum>2&&(sum&1)+(num&1)))puts("YES");else puts("NO");}return 0;
}

谢谢!!!

[BZOJ3895]取石子相关推荐

  1. bzoj3895: 取石子(博弈论,记忆化搜索)

    3895: 取石子 Time Limit: 1 Sec  Memory Limit: 512 MB Submit: 361  Solved: 177 [Submit][Status][Discuss] ...

  2. 洛谷P2252 取石子游戏(威佐夫博弈)

    题目背景 无 题目描述 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后 ...

  3. BZOJ 1874: [BeiJing2009 WinterCamp]取石子游戏(SG函数)

    Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 871  Solved: 365 [Submit][Status][Discuss] Descripti ...

  4. bzoj1874: [BeiJing2009 WinterCamp]取石子游戏

    1874: [BeiJing2009 WinterCamp]取石子游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 834  Solved: 350 ...

  5. 梦工厂实验室 取石子之fans 博弈

    问题 D: 取石子之fans 时间限制: 1 Sec  内存限制: 64 MB 提交: 57  解决: 26 [提交][状态][讨论版] 题目描述 Yougth和Hrdv玩一个游戏,拿出n个石子摆成一 ...

  6. 洛谷 P4706 取石子 解题报告

    P4706 取石子 题目描述 现在 Yopilla 和 yww 要开始玩游戏! 他们在一条直线上标记了 \(n\) 个点,从左往右依次标号为 \(1, 2, ..., n\) .然后在每个点上放置一些 ...

  7. Wannafly 挑战赛16 A 取石子

    题目描述 给出四堆石子,石子数分别为a,b,c,d.规定每次只能从堆顶取走石子,问取走所有石子的方案数. 输入描述: 在一行内读入四个由空格分隔的整数a,b,c,d, 输入均为不超过500的正整数 输 ...

  8. NYOJ 23 取石子

    取石子(一) 时间限制:3000 ms  | 内存限制:65535 KB 难度:2 描述 一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子.游戏的规 ...

  9. 【hdu 1527】取石子游戏

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...

最新文章

  1. egg extend ts_KPL官方给各战队排T次:大王DYG,AG是老2、TS仅K
  2. 深入浅出 Java 微服务视频
  3. 3、Python字典集合
  4. system-copy 和 ShellExecute 用法
  5. 从事仪表专业学c语言有用吗,测控专业就业方向有哪些 就业前景比你想象中的好...
  6. python登录界面实现密码在明文与星号间切换_两个API让星号密码框显示成明文
  7. flume数据采集_大数据采集系统Flume集群部署
  8. java设计模式 建造模式_理解java设计模式之建造者模式
  9. 从源代码中加载res / values / dimension.xml中的维度值
  10. 25. object类中的一些方法分析
  11. 354.俄罗斯套娃信封问题
  12. Service Started!!!-end In Service while
  13. GenBank数据格式
  14. 电脑右键打印不见了_win7右键没有打印选项怎么办|右键菜单没有压缩选项怎么解决|右键没有图形选项解决方法-系统城...
  15. matlab标定 源码,MATLAB标定工具箱
  16. html 上下左右箭头按钮,css 上下左右箭头
  17. 八中计算机是学啥的,邹毅:我与CCF的不解之缘
  18. 【Beetl笔记整理二】定义变量
  19. px和分辨率的关系总结
  20. python引用类全局变量_调用全局变量时无法解析的引用? - python

热门文章

  1. 【python】删除excel表格重复行,数据预处理
  2. 我与 SAP 成都研究院吴院长的二三事
  3. 夏普Sharp SF-S751D 一体机驱动
  4. 识别音标python_音标可以识别单词吗?
  5. 第四章:前缀和、差分(数列)
  6. Jetpack 架构组件:LiveData
  7. Unity----VR摄像机(浅谈)
  8. mysql学习--mysql必知必会
  9. 新手刚学js遇到的ie6问题
  10. deployer部署_Laravel使用CircleCI和Deployer进行连续部署