1 条题解
-
0
自动搬运
来自洛谷,原作者为

KesdiaelKen
**搬运于
2025-08-24 22:14:39,当前版本为作者最后更新于2019-12-19 15:48:15,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
本题为博弈论+数论题目,只需转化一下模型即可。
生成函数只是个随机函数,按题意生成数据。
其实是因为直接给数据文件太大无法上传下面分数据编号进行讲评。
,用数组表示某个状态下为必胜或必败(指的是面对当前局面人的胜负状态)。为末状态,必败。每个状态可以有若干个下接状态(进行一次设计后可以形成的不违规状态)。容易想到,如果所有下接状态均为必胜,则此状态必败;否则必胜。记忆化搜索即可。
用减去每个初始示数,题意就可以理解为在任意一个位置上减,不够减则借位。每个数从到。这不就是进制的减法吗?于是,题意转化为:给出个数,每次减去,为任意自然数,不能减到小于,轮流操作,问谁会面对全的局面。则考虑每个数的胜负情况(记为)。
对于此点,只需考虑一个数的。由于点范围较大,不能像那样枚举下接状态。考虑是否具有规律。发现对于的奇偶不同,规律不同:下面分情况证明:
对于为偶数,当时(败),否则为(胜)。证明:数学归纳法。当时成立。当,由于,,与不同奇偶,则若为偶,所有为奇,,则。为奇同理。
对于为奇数,当,;当,时,时。证明:数学归纳法。当时易知成立。当时,,则类似为偶数时进行归纳。
为偶数的时候也可以转化为以为循环的规律。
规律得出,则可做。
存不下转换后的数。但考虑到最后的数要对取模,可以在读入的时候同时取模。因为是进制,对于奇数位,模的值为乘此位上的数;对于偶数位,模的值为乘上此位上的数。
有多个数,为偶数。先求出每个初始数的。由以上证明可看到为偶数时,赢状态的所有下接状态都为输状态,而输状态的所有下接状态都为赢状态。末状态所有数都为,有偶数个赢状态。对于所有数,一次射击只能将一个数的变为相反的一个状态。因此对于一个人,他面对的所有数中赢状态总数一定。所以,若先手面对奇数个赢状态则必赢,偶数个则必输。
每个数都小于等于,即不可能取到为奇数的特殊状态,等同于为偶数的状态,即赢状态只接输状态,输状态只接赢状态。做法同上。
只有两个数,可以进行特殊讨论解决。
只保存赢或输不能为解决复杂的博弈信息提供足够有效信息。需要使用函数解决(不懂可看sg函数详解或自行查找资料)。令表示数的函数值。同上用数学归纳法可证明:为偶数时,将转为,转为即可;为奇数时,对于,同上转换,否则。之后将每个数的函数值异或,异或值为时必败,否则必胜。
事实上这个结论不用函数也可以推的出来。
标程:
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<string> using namespace std; unsigned long long k,a,b,c,sg,x,lc; inline unsigned long long generate(unsigned long long&a,unsigned long long&b,unsigned long long&c,unsigned long long&k) { a<<=19;a+=b+c; a<<=26;a^=c+=a+81;b--; a<<=7;a>>=(b^c^1145)&14; c*=a;a|=b+=c;a^=b&c; return a%(k+1); } int main() { int n,m,t;scanf("%d",&t); while(t--) { scanf("%lld%d%d%lld%lld%lld",&k,&n,&m,&a,&b,&c); x=0; for(int i=1;i<=n;i++,x^=sg) { sg=0; for(int j=1;j<=m;j++) { lc=generate(a,b,c,k); sg=(sg+((j&1)?(k-lc):(lc+2)))%(k+2); } if((k&1)&&sg==k+1)sg=2; else sg&=1; } if(x)printf("YES\n");else printf("NO\n"); } return 0; }
- 1
信息
- ID
- 4568
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者