• [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 ext{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 ext{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%的数据$1le n le 30000,1 le MAXQ le 20,tle 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
    ");
    81   else printf("lose
    ");
    82 }
    83 int main()
    84 {int T;
    85   cin>>T;
    86   while (T--) work();
    87 }
  • 相关阅读:
    20170419数据结构
    20170418 random函数和range函数
    20170418 sum函数、
    20170417嵌套循环
    20170417循环(loop)
    linux 输入输出重定向
    cut 命令-截取文件中指定内容
    read 命令-从键盘读取变量的值
    xargs-命令
    find 在目录中查找文件
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8399645.html
Copyright © 2020-2023  润新知