[SDOI2016]硬币游戏
2018-02-01 16:17
204 查看
题目描述
Alice 和 Bob 现在在玩的游戏,主角是依次编号为 1 到 n 的 n 枚硬币。每一枚硬币都有两面,我们分别称之为正面和反面。一开始的时候,有些硬币是正面向上的,有些是反面朝上的。Alice 和 Bob 将轮流对这些硬币进行翻转操作,且Alice 总是先手。具体来说每次玩家可以选择一枚编号为 x,要求这枚硬币此刻是反面朝上的。对于编号 x 来说,我们总可以将 x 写成 $ \cdot 2^a \cdot 3^b$ ,其中 a 和 b 是非负整数,c 是与 2,3 都互质的非负整数,然后有两种选择:
选择整数 p,q 满足 $a \ge pq , p \ge 1$ 且 $1 \leq q \leq \text{MAXQ}$ ,然后同时翻转所有编号为 $c \cdot 2^{a-pj} \cdot 3^b$ 的硬币,其中 $j = 0, 1, 2, \ldots q$ 。
选择整数 p,q 满足 $b \geq pq, p \ge 1$ 且 $1 \leq q \leq \text{MAXQ}$ ,然后同时翻转所有编号为 $c \cdot 2^a \cdot 3^{b-pj}c$ 的硬币,其中$j = 0, 1, 2, \ldots q$ 。
可以发现这个游戏不能无限进行下去,当某位玩家无法继续操作上述操作时,便输掉了游戏。作为先手的 Alice,总是希望可以在比赛开始之前就知道自己能否获胜。她知道自己和 Bob 都是充分聪明的,所以在游戏过程中,两人都会最优化自己的策略并尽量保证自己处于不败的情形中。
输入输出格式
输入格式:本题有多组测试数据,第一行输入一个整数T,表示总的数据组数。之后给出T组数据
每组数据第一行输入两个整数n,MAXQ
第二行输入n个整数,第i个数表示第i个硬币的初始状态,0表示反面朝上,1表示正面朝上
输出格式:
输出共有t行。对于每一组数据来说,如果Alice先手必胜,则输出"win"(不包括引号),否则输出"lose"
输入输出样例
暂无测试点说明
对于100%的数据$1\le n \le 30000,1 \le MAXQ \le 20,t\le 100$ 。对于$p=c*2^{i}*3^{j}$求出SG[i][j]
c显然可以无视
那么枚举i,j是log级别的
接下来枚举p,q,再求翻的牌异或和
总复杂度应该是$O(log^{4}n+n)$
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long lol; int lg2,lg3; lol pw2[51],pw3[51],n,MaxQ,SG[51][51],ans; bool vis[300001]; void getSG() {int x; lol i,j,k,p,q; lg2=lg3=0; x=1; while (x<=n) x*=2,lg2++; x=1; while (x<=n) x*=3,lg3++; pw2[0]=pw3[0]=1; for (i=1;i<=lg2;i++) pw2[i]=pw2[i-1]*2; for (i=1;i<=lg3;i++) pw3[i]=pw3[i-1]*3; for (i=0;i<=lg2;i++) { for (j=0;j<=lg3;j++) if (pw2[i]*pw3[j]<=n) { memset(vis,0,sizeof(vis)); for (p=1;p<=i;p++) { for (q=1;q<=MaxQ&&p*q<=i;q++) { int tmp=0; for (k=1;k<=q;k++) { tmp^=SG[i-p*k][j]; } vis[tmp]=1; } } for (p=1;p<=j;p++) { for (q=1;q<=MaxQ&&p*q<=j;q++) { int tmp=0; for (k=1;k<=q;k++) { tmp^=SG[i][j-p*k]; } vis[tmp]=1; } } for (k=0;;k++) if (vis[k]==0) { SG[i][j]=k; break; } } else break; } } void work() {int i,x,y,k1,k2; cin>>n>>MaxQ; getSG(); ans=0; for (i=1;i<=n;i++) { scanf("%d",&x); if (x==0) { y=i;k1=0,k2=0; while (y%2==0) y/=2,k1++; while (y%3==0) y/=3,k2++; ans^=SG[k1][k2]; } } if (ans) printf("win\n"); else printf("lose\n"); } int main() {int T; cin>>T; while (T--) work(); }
相关文章推荐
- [Sdoi2016]硬币游戏
- 【LOJ】#2067. 「SDOI2016」硬币游戏
- 一个硬币移动游戏的求解算法
- 【bzoj2017】[Usaco2009 Nov]硬币游戏
- bzoj 4600 硬币游戏 博弈论
- 硬币游戏1
- Nim-硬币游戏1(Java)
- 洛谷P2964 [USACO09NOV]硬币的游戏A Coin Game
- 硬币游戏 Project Euler 232
- 硬币游戏IV
- hdu 3537 Daizhenyang's Coin(博弈-翻硬币游戏)
- BZOJ 2017 [Usaco2009 Nov]硬币游戏
- 【bzoj4600】【SDOI2016】【硬币游戏】【博弈论+dp】
- 【转】博弈-翻硬币游戏
- bzoj 1411 [ZJOI2009]硬币游戏
- 一个硬币移动游戏的求解算法
- [Sdoi2017]硬币游戏 [高斯消元 KMP]
- bzoj 4820: [Sdoi2017]硬币游戏
- [BZOJ4820] 硬币游戏 - 高斯消元
- bzoj4600 [Sdoi2016]硬币游戏