It's a easy Game Theory......
网上是这么说的,思想倒是不难,但操作起来自己遇到些麻烦。作为一只博弈论入门级别弱脊,于是来写一篇题解总结一下吧,虽然是自己模拟出来的,但中间还是遇到了一丝丝麻烦。大家都知道,所有的后继状态是N状态的某个状态叫做P状态,后继状态中存在一个或多个状态为P状态的某个状态叫做P状态,哎,当时写的时候不知道咋想的,写×了,于是WA了好多次,但今天不仅AC了这道题,也学了若干时间前想巩固使用的一个知识点,那就是C语言的输出数据到文件,庆祝!
先说下题意吧,网上搜的...
从当前日期,玩家可以移动到下一天或下月的同一天。当在下一个月中不存在同一天,则玩家只能移动到下一天。例如,从1924年12月19日,你可以移动到1924年12月20日(下一天),或1925年2月19日(下个月的同一天)。然而,2001年1月31日,你只可以移动到2001年2月1日,因为2001年2月31日是无效的。玩家赢得比赛,仅当他/她到底操作之后到达的日期2001年11月4日。如果一个玩家移动到日期2001年11月4号之后,则算他/她输了比赛。
思路是,(2001 , 11 , 4)是个必败点,能到(2001, 11 , 4)的是必胜点,由时间从后向前推。
网上的大神们是通过打表找到了规律,不过自己真心不想找......那么多数,得扒拉多长时间啊!算了,还是我比较菜的原因。。然后我就用了一个三维数组存的点,然后把所有点的状态都求出来了,打了个表想找规律,数据真心多,看了一小会就不想看了,于是不找规律了,直接交,本以为会TLE的呢,没想到AC了,又暴露了自己复杂度没掌握好的水平了,哎。
下面是我的代码,
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int a[2005][15][35];
FILE *fp;
int check(int a, int b){
int k = 0;
if(a%4==0 && a%100!=0 || a%400==0&&a%100==0) k = 1;
switch(b){
case 1: return 31;
case 2: if(k) return 29; else return 28;
case 3: return 31;
case 4: return 30;
case 5: return 31;
case 6: return 30;
case 7: return 31;
case 8: return 31;
case 9: return 30;
case 10: return 31;
case 11: return 30;
case 12: return 31;
}
}
void getSG(int x, int y, int z){
int i, j, l, k, f, c, flag = 1, t;
for(i = 2001; i >= x; --i)
for(j = 12; j >= 1; --j)
for(l = check(i, j); l >= 1; --l){
if(flag) j = 10, l = 4, flag = 0;
c = i, k = j+1, t = 1;
if(k == 13) k = 1, ++c;
if(l <= check(c, k)) if(a[c][k][l] == 0) t = 0;
if(t){
c = i, k = j, f = l+1;
if(f > check(i, j)) f = 1, ++k;
if(k == 13) k = 1, ++c;
if(a[c][k][f] == 1) a[i][j][l] = 0;
else a[i][j][l] = 1;
}
else a[i][j][l] = 1;
fprintf(fp, "%d-%d-%d--- = %d\n", i, j, l, a[i][j][l]);
if(i == x && j == y && l == z) return;
}
}
int main(){
int t, ak, bk, ck;
memset(a, -1, sizeof a);
cin >> t;
for(int i = 5; i <= 31; ++i){
if(i%2) a[2001][10][i] = 0;
else a[2001][10][i] = 1;
}
a[2001][11][1] = a[2001][11][3] = 1;
a[2001][11][2] = a[2001][11][4] = 0;
fp = fopen("data.txt", "w");
getSG(1900, 1, 1);
fclose(fp);
while(t--){
cin >> ak >> bk >> ck;
if(a[ak][bk][ck]) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
还有一个自己蛮奇怪的事情,会什么不删输出文件那些东西还会AC? 算了,还是因为菜...
然后规律是,不管闰年还是平年,只要月数+天数是个偶数,或者是9月30或者11月30,是必胜点,
其他位置为必败点。
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(0);
int t, n, y, r;
cin >> t;
while(t--){
cin >> n >> y >> r;
if((y+r)%2 == 0 || y == 9 && r == 30 || y == 11 && r == 30)
cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
继续加油!~