隐藏页面特效

[Sdoi2016]硬币游戏

4600: [Sdoi2016]硬币游戏

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 73  Solved: 63
[Submit][Status][Discuss]

Description

Alice和Bob现在在玩的游戏,主角是依次编号为1到n的n枚硬币。每一枚硬币都有两面,我们分别称之为正面和反
面。一开始的时候,有些硬币是正面向上的,有些是反面朝上的。Alice和Bob将轮流对这些硬币进行翻转操作,且
Alice总是先手。具体来说每次玩家可以选择一枚编号为x,要求这枚硬币此刻是反面朝上的。对于编号x来说,我
们总可以将x写成x=c*2^a*3^b,其中a和b是非负整数,c是与2,3都互质的非负整数,然后有两种选择第一种,选择
整数p,q满足a>=p*q,p>=1且1<=q<=MAXQ,然后同时翻转所有编号为c*2^(a-p*j)*3^b的硬币,其中j=0,1,2,..,q。第
二种,选择整数p,q满足b>=p*q,p>=1且1<=q<=MAXQ,然后同时翻转所有编号为c*2^a*3^(b-p*j)的硬币,其中j=0,1,
2,..,q。可以发现这个游戏不能不先进行下去,当某位玩家无法继续操作上述操作时,便输掉了游戏。作为先手的
Alice,总是希望可以在比赛开始之前就知道自己能否获胜。她知道自己和Bob都是充分聪明的,所以在游戏过程中
两人都会最优化自己的策略并尽量保证自己处于不败的情形中

Input

本题有多组测试数据,第一行输入一个整数T,表示总的数据组数。之后给出T组数据
每组数据第一行输入两个整数n,MAXQ
第二行输入n个整数,第i个数表示第i个硬币的初始状态,0表示反面朝上,1表示正面朝上
对于100%的数据1<=n<=30000,1<=MAXQ<=20,t<=100。

Output

输出共有t行。对于每一组数据来说,如果Alice先手必胜,则输出"win"(不包括引号),否则输出"lose"

Sample Input

6
16 14
1 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1
16 14
0 1 0 0 0 1 1 1 1 1 1 0 1 0 0 1
16 11
0 1 0 0 0 1 1 1 0 1 0 0 0 1 0 1
16 12
1 1 1 1 1 1 1 1 0 0 1 1 0 1 1 0
16 4
1 0 0 1 0 0 1 0 0 0 0 1 0 1 1 0
16 20
0 0 0 0 1 0 1 0 0 0 1 0 0 1 0 0

Sample Output

win
lose
win
lose
win
win

HINT

 

Source

  • 首先我们可以发现,每个数的形式都是这样的:c∗2a∗3b
  • 如果我们建立一个二维的坐标系,横坐标表示a,纵坐标表示b,可以这样表示的原因是因为这个游戏的规则。每次翻的点都是c相同的。所以就与c没什么关系了。
  • 这样我们令sg[i][j]表示i这个点与之前所有点的状态不一样,翻这个点的sg值是多少。那么转移可以去暴力枚举后继局面,即我们去枚举去2的因子,和去3的因子,那么能够达到的后继局面sg值就是所有枚举到的后继状态的异或和。
  • 有一个问题就是在一个后继状态中会被翻的所有的点得sg值怎么表示?在计算答案的过程中翻一个点会不会对前面的点有影响?
  • 其实这两个是一个问题,就是这个点和它的后继点是否是独立的。
  • 其实是独立的。我们可以看求sg的过程,假如我们翻了这个点后会对前面有些点产生影响,但是对于某一个点来说被翻得总次数是一定的,只是先后顺序不同,所以无论顺序是怎样这个点的状态都会是这个,也就是说这个点可以看成是独立的。
#include<cstdio> #include<cstring> using namespace std; inline void read(int &x){ register char ch=getchar();x=0; while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } bool flag[500]; int T,n,maxq,SG[20][20]; inline void divide(int x,int &n2,int &n3){ for(n2=0;x&1^1;x>>=1) n2++; for(n3=0;!(x%3);x/=3) n3++; } inline void log(int x,int &n2,int &n3){ int v; for(v=x,n2=0;v>1;v>>=1) n2++; for(v=x,n3=0;v>2;v/=3) n3++; } inline void dp(){ memset(SG,0,sizeof SG); int x,y;log(n,x,y); for(int i=0;i<=x;i++){ for(int j=0;j<=y;j++){ memset(flag,0,sizeof flag); for(int p=1;p<=i;p++){ for(int q=1;q<=maxq&&p*q<=i;q++){ int o=-1; for(int k=1;k<=q;k++){ o=(~o)?o^SG[i-p*k][j]:SG[i-p*k][j]; } if(~o) flag[o]=1; } } for(int p=1;p<=j;p++){ for(int q=1;q<=maxq&&p*q<=j;q++){ int o=-1; for(int k=1;k<=q;k++){ o=(~o)?o^SG[i][j-p*k]:SG[i][j-p*k]; } if(~o) flag[o]=1; } } for(int o=0;;o++) if(!flag[o]){SG[i][j]=o;break;} } } } int main(){ int o,o2,o3,now(0); for(read(T);T--;now=0){ read(n);read(maxq);dp(); for(int i=1;i<=n;i++){ read(o);if(o) continue; divide(i,o2,o3); now^=SG[o2][o3]; } puts(now?"win":"lose"); } return 0; }

 

 

__EOF__

本文作者shenben
本文链接https://www.cnblogs.com/shenben/p/6851846.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   神犇(shenben)  阅读(933)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示