洛谷P2953[USACO09OPEN]牛的数字游戏Cow Digit Game

洛谷P2953[USACO09OPEN]牛的数字游戏Cow Digit Game

传送门

题目描述

贝茜和约翰在玩一个数字游戏.贝茜需要你帮助她.

游戏一共进行了G(1≤G≤100)场.第i场游戏开始于一个正整数Ni(l≤Ni≤1,000,000).游

戏规则是这样的:双方轮流操作,将当前的数字减去一个数,这个数可以是当前数字的最大数码,也可以是最小的非0数码.比如当前的数是3014,操作者可以减去1变成3013,也可以减去4变成3010.若干次操作之后,这个数字会变成0.这时候不能再操作的一方为输家. 贝茜总是先开始操作.如果贝茜和约翰都足够聪明,执行最好的策略.请你计算最后的赢家.

比如,一场游戏开始于13.贝茜将13减去3变成10.约翰只能将10减去1变成9.贝茜再将9减去9变成0.最后贝茜赢.

输入样例:

2 
9 
10 

输出样例:

YES 
NO 

在我第一次写的题解上进行了一点小小的改动,看着更舒服一点了。

这题曾经的我第一眼看到的反应是深搜,然后就会发现对于每个测试点,都有多组数据,于是便会想到直接跑完所有数字。那么问题就是怎么跑了

首先对于1-9,谁先遇到这个数字,谁就赢了。那么我们定义数组vis[i][2]

vis[i][0]表示贝茜先遇到数字i能不能赢。

vis[i][1]表示约翰先遇到数字i能不能赢。

那么对于数字i,找到他的最大的数字ma和最少的数字mi

那么vis[i][0]的状态就可以用vis[i-ma][1]和vis[i-mi][1]来得到

约翰的状态以此类推。

#include <iostream>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
bool vis[1000010][2];
struct ss{int minx,maxy;};
ss getmix(int x)
{
    int wow=0,mx=0,mn=0xfffffff;
    ss ret;
    while(x>=1)
    {
        int p=x%10;
        mx=max(mx,p);
        if(p!=0)
            mn=min(mn,p);
        x/=10;
    }
    ret.minx=mn;
    ret.maxy=mx;
    return ret;
}
void work()
{
    for(int i=10;i<=1000000;i++)
    {
        ss wo=getmix(i);
        int chos1=wo.maxy,chos2=wo.minx;
        if(!vis[i-chos1][1]||!vis[i-chos2][1])
            vis[i][0]=1;
        if(!vis[i-chos1][0]||!vis[i-chos2][0])
            vis[i][1]=1;
    }
}
int main()
{
    for(int i=1;i<=9;i++)
        vis[i][0]=true,vis[i][1]=true;
    work();
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int x;
        scanf("%d",&x);
        if(vis[x][0])
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

写完之后你会发现,vis[i][0]和vis[i][1]这两个数组是完全相同的

在这个基础上我们还可以对两个vis这个二维数组进行简化

让vis[i]表示以i这个状态为起点先手必败或先手必胜。

用同样的方法转移vis数组,就可以记录谁胜谁负了

猜你喜欢

转载自blog.csdn.net/u014085852/article/details/81293571