zoukankan      html  css  js  c++  java
  • JZOJ 3033. 【NOIP2012模拟10.17】石子游戏

    题目

    Description



    两人取一堆n个石子 先手不能全部取完 之后每人取的个数不能超过另一个人上轮取的数*K。取完最后一个石子的人获胜。给n,K判断先手必胜并求第一步。


     

    Input



    输入文件名为 stone.in。


    第一行为一个正整数t(1<=t<=10),表示共t组测试数据


    接下来t行,每行包括两个正整数n,k


    Output



    输出文件名为stone.out。


    共t行,第i行先输出“Case i: ”(不包括引号),接着输出结果,若先手有必胜策略则输出第一次取的石子数(答案不唯一,输出第一步最小选几),否则输出lose。


     

    Sample Input

    5 
    16 1 
    11 1 
    32 2 
    34 2 
    19 3
    

    Sample Output

    Case 1: lose
    Case 2: 1
    Case 3: 3
    Case 4: lose
    Case 5: 4
    
     

    Data Constraint

     
     

    Hint



    对于10%的数据k=1;


    对于30%的数据1<=k<=2;


    对于100%的数据2<=n<=100000000,1<=k<=100000。

     

    分析

     

    • 本题是个博弈论
    • 我看其他人都是把题解co上去的
    • 所以我手动分析一波
    • 首先,k=1就是转成二进制
    • 而k=2就是斐波那契数列
    • 那就让我来论证一下k=1
    • 首先现在有一个数,n=24
    • 二进制是11000
    • 我们取最后一个1 得到 10000
    • 然后对手只能破坏我刚刚1后面的零 可能会变成10110 10010 10011
    • 然后我就会去把1变成0
    • 最后数就只剩下一个1给对手了,而只有一个1是肯定lose的
    •    简单说就是对手添1我补0所以剩下最后一个肯定是给他的
    • 然后我们来讨论一下我们k>3的数列构建问题
    • 我只能口胡一下,望理解
    • 首先,核心代码如下

      while (a[i]<n)
      {
      i++;
      a[i]=b[i-1]+1;
      while (a[j+1]*k<a[i]) 我要找到一个刚好*k小于我当前a[i]的数  
      j++;
      if (a[j]*k<a[i]) b[i]=b[j]+a[i]; 然后这里是干什么呢因为a[i]=b[i-1]+1,所以b[i]=b[j]+b[i-1]+1; 当是为什么我a[i]=b[i]+1呢??看下面
      else b[i]=a[i];
      }

    • 我们当k=1是不是就是二进制 比如我们的1000,破坏前边的1
    • 是不是可能成为0111,那我们的0111+1不就等于1000吗
    • 我们数列需要一个数是可以被另外其他多个数组组成的,那不就成立了吗

     

    代码

     1 #include<bits/stdc++.h>
     2 const int MAX=2000000;
     3 int a[MAX],b[MAX],n,m,C,num=0;
     4 
     5 int main()
     6 {
     7     for(scanf("%d",&C);C--;)
     8     {
     9         scanf("%d%d",&n,&m);
    10         a[0]=b[0]=1;
    11         int i=0,j=0;
    12         while(a[i]<n)
    13         {
    14             i++;
    15             a[i]=b[i-1]+1;
    16             while(a[j+1]*m<a[i]) j++;
    17             if(a[j]*m<a[i]) b[i]=b[j]+a[i];
    18             else b[i]=a[i];
    19         }
    20         printf("Case %d: ",++num);
    21         if(a[i]==n)
    22         {
    23             puts("lose");
    24             continue;
    25         }
    26         int ans;
    27         while(n)
    28         {
    29             if(n>=a[i]) n-=a[i],ans=a[i];
    30             i--;
    31         }
    32         printf("%d
    ",ans);
    33     }
    34     return 0;
    35 }

     

    为何要逼自己长大,去闯不该闯的荒唐
  • 相关阅读:
    Numpy学习笔记练习代码 ——(二)
    Requests爬取表格数据并存入CSV中
    Numpy学习练习代码 ——(一)
    Requests爬取中文网站乱码问题
    Pycharm用Ctrl+鼠标滚轮控制字体大小
    一、Windows10下python3和python2同时安装
    inux下配置rsyncd服务
    shell 脚本中$$,$#,$?分别代表什么意思?
    linux shell awk 流程控制语句(if,for,while,do)详细介绍
    定时任务
  • 原文地址:https://www.cnblogs.com/zjzjzj/p/11141482.html
Copyright © 2011-2022 走看看