给一个长度为6的有前导零的数字,每次可以使一位减少,最少减少1,最多减少到0,也可以在0右边的数字和0本身都删除,两人轮流操作,问先手是否必胜
一开始看错题,写了半天都不对,一种是SG函数的,发现SG函数vis数组范围是SG的选择,另一种是顺推的DP,DP要快很多
SG函数 1680ms
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const double PI = acos(-1.0);
template <class T> inline T MAX(T a, T b){if (a > b) return a;return b;}
template <class T> inline T MIN(T a, T b){if (a < b) return a;return b;}
const int N = 111;
const int M = 11111;
const LL MOD = 1000000007LL;
const int dir[4][2] = {1, 0, -1, 0, 0, -1, 0, 1};
const int INF = 0x3f3f3f3f;
int sg[10][10][10][10][10][10][10];
int cg(int l, int a[10])
{
int b[10], i, j, k;
int & ans = sg[l][a[0]][a[1]][a[2]][a[3]][a[4]][a[5]];
if (l == 0)
{
ans = 0;
return 0;
}
bool v[61];
memset(v, false, sizeof(v));
if (ans != -1) return ans;
for (i = 0; i < l; ++i)
{
if (a[i] != 0)
{
for (j = 1; j <= a[i]; ++j)
{
a[i]-=j;
k = cg(l, a);
v[k] = 1;
a[i]+=j;
}
}
if (a[i] == 0)
{
for (j = i; j < l; ++j)
{
b[j] = a[j];
a[j] = 0;
}
k = cg(i, a);
v[k] = 1;
for (j = i; j < l; ++j)
a[j] = b[j];
}
}
i = 0;
while (v[i]) i++;
ans = i;
// printf("%d %d %d %d %d %d %d: %d\n", l, a[0], a[1], a[2], a[3], a[4],a[5], ans);
return ans;
}
int main()
{
char str[10];
memset(sg, -1, sizeof(sg));
while (scanf("%s", str) != EOF)
{
int l, num[6], i, j, k;
l = strlen(str);
memset(num, 0, sizeof(num));
for (i = 0; i < l; ++i)
{
num[i] = str[i] - '0';
}
if (num[0] == 0) {printf("Yes\n"); continue;}
if (cg(l, num) != 0)printf("Yes\n");
else printf("No\n");
}
return 0;
}
DP 30ms
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const double PI = acos(-1.0);
template <class T> inline T MAX(T a, T b){if (a > b) return a;return b;}
template <class T> inline T MIN(T a, T b){if (a < b) return a;return b;}
const int N = 111;
const int M = 11111;
const LL MOD = 1000000007LL;
const int dir[4][2] = {1, 0, -1, 0, 0, -1, 0, 1};
const int INF = 0x3f3f3f3f;
bool dp[1111111];
int callen(int x)
{
int m = 0;
while (x)
{
x /= 10;
m++;
}
return m;
}
void solve(int x)
{
int q, lim, m = x, l, bas = 1, i, j, k;
l = callen(m);
for (i = 0; i < l; ++i)
{
lim = (m / bas) % 10; q = m;
for (j = 0; j < 9 - lim ; ++j)
{
q += bas;
dp[q] = 1;
}
bas *= 10;
}
if (l < 6)
{
k = 6 - l; m = x;
bas = 1;
for (j = 0; j < k; ++j)
{
m *= 10;
for (i = 0; i < bas; ++i)
dp[m + i] = 1;
bas *= 10;
}
}
}
void init()
{
memset(dp, false, sizeof(dp));
dp[0] = true;
for (int i = 1; i <= 999999; ++i)
{
if (!dp[i]) solve(i);
}
}
int main()
{
char str[10];
init();
while (scanf("%s", str) != EOF)
{
int n, l;
l = strlen(str);
if (str[0] == '0')
{
printf("Yes\n");
continue;
}
n = 0;
for (int i = 0; i < l; ++i)
n = n * 10 + str[i] - '0';
if (dp[n]) printf("Yes\n");
else printf("No\n");
}
return 0;
}