HDU2486 A simple stone game 博弈论

20 篇文章 0 订阅

题目链接:HDU2486

A simple stone game

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 568    Accepted Submission(s): 324


Problem Description
After he has learned how to play Nim game, Mike begins to try another stone game which seems much easier.

The game goes like this: Two players start the game with a pile of n stones. They take stones from the pile in turn and every time they take at least one stone. The one who goes first can take at most n-1 stones for his first move. From then on a player can take at most k times as many stones as his opponent has taken last time. For example, if one player take m stones in his turn, then the other player can take at most k × m stones next time. The player who takes the last stone wins the game. Suppose that those two players always take the best moves and never make mistakes, your job is to find out who will definitely win the game.
 

Input
The first line contains a integer t, indicating that there are t test cases following.(t<=20).

Each test case is a line consisting of two integer n and k.(2<=n<=10^8,1<=k<=10^5).
 

Output
For each test case, output one line starting with “Case N: ”, N is the case number. And then, if the first player can ensure a winning, print the minimum number of stones he should take in his first turn. Otherwise, print "lose". Please note that there is a blank following the colon.
 

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
 
题意:有n个石子,先手第一次最多取n-1个,之后如果前一个人取m个,则下一个人可以取1到km个,取完最后一个为胜,问先手是否会胜,如果会胜输出第一次取几个。
题目分析:这是一个叫做k倍动态减法的问题,具体可以参考曹钦翔从“k倍动态减法游戏”出发探究一类组合游戏问题的论文。
首先考虑k=1的情况,必败态为2的次方数,对必胜态,将个数二进制分解,每次取低位的1,对面肯定无法一次将剩下的所有取完。每次取最低位会必胜。
对于k=2的情况,必败态为fibonacci数,一个很重要的性质就是任意整数n都可以分解为不相邻的fibonacci数相加,不相邻的2个数之间差距2倍以上,因此可以分解后每次取最小位。
对于k>2的情况,参考上面,我们需要构造一个数列使得每个整数可以由数列中若干个数相加并且这些数倍数差距大于k,我们用a来存这些数,用b来表示前i-1个能构成的最大的数,那么a[i+1]=b[i]+1;然后再构造b[i+1],由于b[i+1]要用到a[i+1],并且不相邻,因此要找到a[j]*k<a[i],b[i+1]=a[i+1]+b[j]。
查询时只需要不断减去最大的a[i]直到0,最后剩下的就是第一次取的值。
//
//  main.cpp
//  A simple Stone Game
//
//  Created by teddywang on 2016/10/4.
//  Copyright © 2016年 teddywang. All rights reserved.
//
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2000000;
int a[maxn],b[maxn];
int main()
{
    int t,n,k;
    cin>>t;
    for(int cas=1;cas<=t;cas++)
    {
        cin>>n>>k;
        printf("Case %d: \n",cas);
        if(n<=k+1)
        {
            printf("lose\n");
            continue;
        }
        a[0]=b[0]=1;
        int i=0,j=0;
        while(a[i]<n)
        {
            i++;
            a[i]=b[i-1]+1;
            while(a[j+1]*k<a[i]) j++;
            if(a[j]*k<a[i]) b[i]=b[j]+a[i];
            else b[i]=a[i];
        }
//        for(int l=0;l<=i;l++)
//            cout<<a[l]<<" ";
//        cout<<endl;
//        for(int l=0;l<=j;l++)
//            cout<<b[l]<<" ";
//        cout<<endl;
        if(a[i]==n)printf("lose\n");
        else
        {
            int ans=0;
            while(n)
            {
                if(n>=a[i])
                {
                    n-=a[i];
                    ans=a[i];
                }
                i--;
            }
            cout<<ans<<endl;
        }
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值