洛谷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数组,就可以记录谁胜谁负了