【Day2P3,头痛的博弈】取石子游戏 题解

      OI林林总总的题目中,本人最头痛的就是传说中的博弈问题。什么叫最优选择?咋的会有什么必胜策略?晕啊/o\...

      悲剧的是,C老师的测试题中偏偏加了这种题…对于只会输出“0”的我来说(当然偶数只能取1我也发现了~),题解中那句“本题一定有解”注定了我那次测试悲惨的命运…

 

 

  
  
【题目描述】
这里有K块石头(
3 <= k <= 10 ^ 10 ),两个人轮流来取这些石头。每次最多取L块(L > 0 ),最少
取1块。对于输入的k,判断是否存在一个L,使得第二个取的人有必胜的策略,如果有,输出
最小的L;如果没有,则输出0。
【输入格式】
第一行为一个正整数T,表示数据的组数。接下来T行,每行一个正整数K(
1 <= T <= 1000 )
【输出格式】
输出共T行,为T组数据的解答,每行为满足条件的最小L或0
【样例输入】
1
3
【样例输出】
2

 

      据同学说,很Easy的一道博弈…觉得无从下手的童鞋们,可以往下看。

      很显然,如果k是一个偶数,则结果一定是1(也就是一个一个的取)。然而偶数呢?

      简单分析,如果每次取k-1个,那么第二个取的人一定会赢。但是题目要求输出的是最小解。有了前面分析的结果,我们可以将题目进行转化。

      我们有15个石子。由于我们知道了“每次取k-1”这一必胜策略,那么,我们可以将整体必胜转化为局部必胜,也就是说,将他们分组。

      首先把他们分成三组。那么每次取4,则第二个取的必胜。

      其次我们可以把他们分成5组,这样每次取两个,第二个取的人必胜。

      因为题目要求输出最小的L,那么我们的任务就变成,找到k的最小的约数。这也就是偶数的答案是1的原因。

      这样主要的困难就是找约数。可以证明,最小的约数一定是一个质数。数据范围很大,那么我们可以打一个1到10^5的质数表。嗯,就这样了。

 

参考代码(省略质数表):

 

  
  
1 program game;
2 const
3 z: array [ 1 .. 9592 ] of longint = (质数表);
4 var
5 i,j:longint;
6 k,p,t:int64;
7 begin
8 readln(t);
9 for i: = 1 to t do
10 begin
11 p: = 0 ;
12 readln(k);
13 for j: = 1 to 9592 do // 简单的枚举
14 if k mod z[j] = 0 then
15 begin
16 p: = j;
17 break;
18 end ;
19 if p = 0 then writeln(k - 1 ) // 处理大质数
20 else writeln(z[p] - 1 );
21 end ;
22 END.

(saltless原创,转载请注明出处)

你可能感兴趣的:(游戏)