2021牛客暑期多校训练营1 - A - Alice and Bob - 题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营1 - A - Alice and Bob - 题解相关的知识,希望对你有一定的参考价值。

2021牛客暑期多校训练营1 - A - Alice and Bob

传送门
Time Limit: 1 second
Memory Limit: 262144K

题目描述

Alice and Bob like playing games. There are two piles of stones with numbers n {n} n and m {m} m. Alice and Bob take turns to operate, each operation can take away k ( k > 0 ) {k}(k>0) k(k>0) stones from one pile and take away s × k ( s ≥ 0 ) s \\times k(s \\geq 0) s×k(s0) stones from another pile. Alice plays first. The person who cannot perform the operation loses the game.

Please determine who will win the game if both Alice and Bob play the game optimally.

输入描述:

The first line contains an integer T ( 1 ≤ T ≤ 1 0 4 ) T(1 \\le T \\le 10^4) T(1T104) denotes the total number of test cases.
Each test case contains two integers n , m ( 1 ≤ n , m ≤ 5 × 1 0 3 ) n,m(1 \\le n,m \\leq 5 \\times 10^3) n,m(1n,m5×103) in a line, indicating the number of two piles of stones.

输出描述:

For each test case, print “Alice” if Alice will win the game, otherwise print “Bob”.

样例

样例一

输入

5
2 3
3 5
5 7
7 5
7 7

输出

Bob
Alice
Bob
Bob
Alice

题目大意

爱丽丝和鲍勃玩石子游戏,每次从两堆石子中取出一些石子,满足:

  • 不能不取
  • 取出数量是倍数关系(可以是0倍)

第一个没石头可取的人输。女士优先且两人都非常明智,问爱丽丝先手谁赢。

解题思路

  • 该我时,如果已经没有石头可取了,我就输了
  • 该我时,如果我取走一些石头后,下一个人必输,我就赢了
  • 该我时,如果无论我怎么取,都不能使得下一个人必输,我就输了

可以用上面的方法在小数据范围内模拟,生成所有输赢的情况,找规律。
然后发现先手输的可能性很小,只有1359种可能。于是想到了打表,把先手输的情况记录下来。

这是如何判断一个状态是输还是赢

int win[5010][5010]={0}; // 0:未处理  1:win  2:lose
bool ifWin(int m, int n)
{
    if(m>n)swap(m,n); // 让m<=n
    if(win[m][n])return win[m][n]==1; // 算过了,直接返回
    for(int i=1;i<=m;i++) // 模拟所有情况
    {
        int t=n/i;
        for(int j=0;j<=t;j++)
        {
            if(!ifWin(m-i,n-i*j)) // 能一步拿到输的状态,就赢了
            {
                win[m][n]=1;
                return true;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        int t=m/i;
        for(int j=0;j<=t;j++)
        {
            if(!ifWin(m-j*i,n-i)) // 能一步拿到输的状态,就赢了
            {
                win[m][n]=1;
                return true;
            }
        }
    }
    // 不能到下一个人输的状态,自己就输了
    win[m][n]=2;
    return false;
}

测试一些数据是否正确

void testForWin()
{
    int a,b;
    while(cin>>a>>b)
    {
        cout<<ifWin(a,b)<<endl;
    }
    exit(0);
}

打表生成20*20的输赢图

void prtAll()
{
    int M = 20;
    printf("   ");
    for(int i=1;i<=M;i++)
    {
        printf("%2d",i);
    }
    puts("");
    for(int i=1;i<=M;i++)
    {
        printf("%2d: ",i);
        for(int j=1;j<=M;j++)
        {
            if(j>=i)
                cout<<ifWin(i,j)<<' ';
            else
                cout<<"  ";
        }
        puts("");
    }
}

打表输出所有的输的情况

void prtLose(int M)
{
    int cnt=0;
    for(int i=1;i<=M;i++)
    {
        // printf("i=%d\\n",i);
        for(int j=i;j<=M;j++)
        {
            if(!ifWin(i,j))
            {
                cnt++;
                printf("{%d,%d},",i, j);
            }
        }
    }
    // cout<<cnt<<endl;
    system("pause");
}

AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int win[5010][5010]={0}; // 0:未处理  1:win  2:lose
bool ifWin(int m, int n)
{
    if(m>n)swap(m,n); // 让m<=n
    if(win[m][n])return win[m][n]==1;
    for(int i=1;i<=m;i++)
    {
        int t=n/i;
        for(int j=0;j<=t;j++)
        {
            if(!ifWin(m-i,n-i*j)) // 能一步拿到输的状态,就赢了
            {
                win[m][n]=1;
                return true;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        int t=m/i;
        for(int j=0;j<=t;j++)
        {
            if(!ifWin(m-j*i,n-i)) // 能一步拿到输的状态,就赢了
            {
                win[m][n]=1;
                return true;
            }
        }
    }
    win[m][n]=2;
    return false;
}
void testForWin()
{
    int a,b;
    while(cin>>a>>b)
    {
        cout<<ifWin(a,b)<<endl;
    }
    exit(0);
}
void prtAll()
{
    int M = 20;
    printf("   ");
    for(int i=1;i<=M;i++)
    {
        printf("%2d",i);
    }
    puts("");
    for(int i=1;i<=M;i++)
    {
        printf("%2d: ",i);
        for(int j=1;j<=M;j++)
        {
            if(j>=i)
                cout<<ifWin(i,j)<<' ';
            else
                cout<<"  ";
        }
        puts("");
    }
}
void prtLose(int M)
{
    int cnt=0;
    for(int i=1;i<=M;i++)
    {
        // printf("i=%d\\n",i);
        for(int j=i;j<=M;j++)
        {
            if(!ifWin(i,j))
            {
                cnt++;
                printf("{%d,%d},",i, j);
            }
        }
    }
    // cout<<cnt<<endl;
    system("pause");
}
//1359
int cannot[][2]={{2,3},{5,7},{9,12},{11,15},{14,20},{17,22},{19,33},{24,32},{26,35},{28,58},{29,40},{31,38},{37,53},{42,52},{44,75},{45,60},{47,65},{49,70},{50,62},{55,68},{57,79},{64,87},{67,86},{72,92},{74,99},{77,101},{81,174},{82,118},{83,110},{85,113},{89,123},{90,116},{94,129},{95,127},{97,126},{103,136},{105,199},{106,146},{108,145},{112,166},{115,246},{120,161},{122,160},{125,164},{131,309},{132,182},{133,177},{135,198},{138,180},{139,156},{141,239},{142,190},{143,186},{148,203},{149,195},{151,340},{152,197},{154,232},{158,218},{163,229},{168,215},{170,286},{171,228},{172,224},{176,350},{179,298},{184,253},{185,236},{188,268},{189,259},{192,241},{194,256},{201,266},{205,281},{207,274},{208,264},{210,271},{212,322},{213,317},{214,278},{217,289},{220,327},{221,280},{223,315},{226,301},{231,332},{234,307},{238,372},{