您的位置:首页 > 其它

hdu2486 hdu2580 poj3922 A simple stone game--K倍动态减法游戏 博弈

2012-09-16 09:05 316 查看

A simple stone game

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 182 Accepted Submission(s): 86



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


Source
2008 Asia Regional Beijing

Recommend
gaojie

这三题都是同一题。
这就是K倍动态减法游戏,可以参考曹钦翔从“k倍动态减法游戏”出发探究一类组合游戏问题的论文。
首先k=1的时候,必败态是2^i,因为我们把数二进制分解后,拿掉最后一个1,那么会导致对方永远也取不完,我们可以拿到最后一个1.
k=2的时候,必败态是斐波那契数列,因为任何一个整数n都可以写成两项斐波那契数的和,所以我们拿掉1,对方永远取不完高两位的数。
k的时候我们必须构造数列,将n写成数列中一些项的和,使得这些被取到的项的相邻两个倍数差距>k 那么每次去掉最后一个1 还是符合上面的条件。设这个数列已经被构造了i 项,第 i 项为a[ i ],前 i 项可以完美对1..b[ i ] 编码使得每个编码的任意两项倍数>K 那么有

a[ i+1 ] = b[ i ] + 1;这是显然的 因为b[ i ] + 1没法构造出来,只能新建一项表示

然后计算b[ i+1] 既然要使用 a[ i+1 ] 那么下一项最多只能是某个 a[ t ] 使得 a[ t ] * K < a[ i+1 ] 于是

b[ i ] = b[ t ] + a[ i+1 ]

然后判断n是否在这个数列里面

如果在,那么先手必败。否则不停的减掉数列a中的项构造出n的分解,最后一位就是了。
#include<iostream>
#include<cstdlib>
#include<stdio.h>
using namespace std;
const int N=2000000;
int a
,b
;
int main()
{
    int t,n,k;
    int count=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        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];
        }
        printf("Case %d: ",count++);
        if(a[i]==n) puts("lose");
        else
        {
            int ans;
            while(n)
            {
                if(n>=a[i])
                {
                    n-=a[i];
                    ans=a[i];
                }
                i--;
            }
            cout<<ans<<endl;
        }

    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: