[SDOI2016]硬币游戏

题目描述

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)$

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long lol;
 8 int lg2,lg3;
 9 lol pw2[51],pw3[51],n,MaxQ,SG[51][51],ans;
10 bool vis[300001];
11 void getSG()
12 {int x;
13   lol i,j,k,p,q;
14   lg2=lg3=0;
15   x=1;
16   while (x<=n) x*=2,lg2++;
17   x=1;
18   while (x<=n) x*=3,lg3++;
19   pw2[0]=pw3[0]=1;
20   for (i=1;i<=lg2;i++)
21     pw2[i]=pw2[i-1]*2;
22   for (i=1;i<=lg3;i++)
23     pw3[i]=pw3[i-1]*3;
24   for (i=0;i<=lg2;i++)
25     {
26       for (j=0;j<=lg3;j++)
27     if (pw2[i]*pw3[j]<=n)
28     {
29       memset(vis,0,sizeof(vis));
30       for (p=1;p<=i;p++)
31         {
32           for (q=1;q<=MaxQ&&p*q<=i;q++)
33         {
34           int tmp=0;
35           for (k=1;k<=q;k++)
36             {
37               tmp^=SG[i-p*k][j];
38             }
39           vis[tmp]=1;
40         }
41         }
42       for (p=1;p<=j;p++)
43         {
44           for (q=1;q<=MaxQ&&p*q<=j;q++)
45         {
46           int tmp=0;
47           for (k=1;k<=q;k++)
48             {
49               tmp^=SG[i][j-p*k];
50             }
51           vis[tmp]=1;
52         }
53         }
54       for (k=0;;k++)
55         if (vis[k]==0)
56           {
57         SG[i][j]=k;
58         break;
59           }
60     }
61     else break;
62     }
63 }
64 void work()
65 {int i,x,y,k1,k2;
66   cin>>n>>MaxQ;
67   getSG();
68   ans=0;
69   for (i=1;i<=n;i++)
70     {
71       scanf("%d",&x);
72       if (x==0)
73     {
74       y=i;k1=0,k2=0;
75       while (y%2==0) y/=2,k1++;
76       while (y%3==0) y/=3,k2++;
77       ans^=SG[k1][k2];
78     }
79     }
80   if (ans) printf("win\n");
81   else printf("lose\n");
82 }
83 int main()
84 {int T;
85   cin>>T;
86   while (T--) work();
87 }

 

posted @ 2018-02-01 16:17  Z-Y-Y-S  阅读(436)  评论(2编辑  收藏  举报