[JZOJ4024] 石子游戏

Description
  Alice 和 Bob 总喜欢聚在一起玩游戏(T_T),今天他(她)们玩的是一款新型的取石子游戏。游戏一开始有N堆石子,Alice 和 Bob 轮流取出石子。在每次操作中,游戏者必须选择其中的一堆石子,并作出下列的其中一种操作:
  (1)移去整堆石子
  (2)假设石子堆中有X颗石子,取出Y颗石子,其中1<=Y    
  游戏结束的条件是:取出最后一颗石子的人胜出。众所周知,Alice和Bob都是绝顶聪明的,假设他们在游戏中都采取最优的策略,问最后谁会胜出游戏呢?

  Alice先取。
Input
  第一行包含一个整数T,表示测试数据的组数。
  接下来T组测试数据,在每组数据中,第一行包含一个整数N,表示有多少堆石子。第二行N个正整数,分别表示每堆有多少颗石子。
Input
  第一行包含一个整数T,表示测试数据的组数。
  接下来T组测试数据,在每组数据中,第一行包含一个整数N,表示有多少堆石子。第二行N个正整数,分别表示每堆有多少颗石子。
Sample Input
  3
  3
  3 5 6
  4
  2 3 6 9
  5
  3 2 1 1000000 999999
Sample Output
  Alice
  Bob
  Alice
Data Constraint
  20%的数据,N<=5,每堆石子数量少于10
  100%的数据,T<=100,N<=100,每堆石子数量不大于1,000,000

Summary

  题目还有个条件是取第k堆石头j个,j与第k堆石头数互质。

  然后构造SG函数。

  若石头数是质数,那么对于小于 i 的所有正整数都可以被取到,那么 SGi则是它在质数表的排名+1。 

  若石头数是一个合数,那么 i 肯定存在某个因子为前面出现过的质数,那么 SGi 就应为最小质因子的 SG 值了。

  最后如果所有的SG值xor后为0,后手必胜,否则先手必胜。

Code

 1 #include<cstdio>
 2 using namespace std;
 3 int n,m,i,j,z[500000],sg[1000000];
 4 bool a[1000000];
 5 int main()
 6 {
 7     scanf("%d",&n);
 8     a[1]=true;
 9     int ma=1000000;    
10     for (int i=2;i<=1000;i++)
11         for (int j=2;j<=ma/i;j++)
12             a[i*j]=true;
13     int sum=0;
14     sg[1]=1;
15     for (int i=1;i<=ma;i++)
16         if (not a[i]) 
17         {
18             sum++;
19             z[sum]=i;
20             sg[i]=sum+1;
21         }
22         else
23         for (int j=1;j<=sum;j++)
24             if (i%z[j]==0)
25             {
26                 sg[i]=sg[z[j]];
27                 break;
28             }
29     for (int i=1;i<=n;i++)
30     {
31         scanf("%d",&m);
32         int ans=0;
33         for (int j=1;j<=m;j++)
34         {
35             int x;
36             scanf("%d",&x);
37             ans=ans^sg[x];
38         }
39         if (ans==0) printf("Bob\n");
40         else printf("Alice\n");
41     }
42 }
View Code

 

转载于:https://www.cnblogs.com/Tokisaki-Kurumi/p/9316307.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值