题目:从1900,1,1到2001,11,4中给出一个日期,游戏者轮流操作,每个人可以选择移到下一个日期,或者选择到下一个月的相同日历日,当然这都是在合理的情况下进行操作,谁先到达2001,11,4谁胜,问是否先手必胜
思路:利用NP状态定理,直接预处理出来
代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3fn
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
//0x3f3f3f3f
int mon[2][13]={
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}
};
int sg[105][13][35];
bool judge(int y){
y+=1900;
if(y%400==0) return 1;
if(y%100!=0&&y%4==0) return 1;
return 0;
}
void init_sg(){
mm(sg,-1);
sg[101][11][4]=0;//标记为P状态
for(int i=5;i<=mon[0][11];i++) sg[101][11][i]=1;//标记为N状态
for(int i=1;i<=mon[0][12];i++) sg[101][12][i]=1;//标记为N状态
for(int y=101;y>=0;y--)
for(int m=12;m>=1;m--){
for(int d=mon[judge(y)][m];d>=1;d--){
if(sg[y][m][d]!=-1) continue;
int y1=y,m1=m+1,d1=d;
int y2=y,m2=m,d2=d+1;
if(m1>12){
m1=1;
y1++;
}
if(d2>mon[judge(y2)][m2]){
d2=1;
m2++;
}
if(m2>12){
m2=1;
y2++;
}
if(d1<=mon[judge(y1)][m1]){
if(sg[y1][m1][d1]==1&&sg[y2][m2][d2]==1)
sg[y][m][d]=0;
else
sg[y][m][d]=1;
}
else
sg[y][m][d]=!sg[y2][m2][d2];
}
}
}
int main(){
int T,y,m,d;
init_sg();
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&y,&m,&d);
if(sg[y-1900][m][d]) printf("YES\n");
else printf("NO\n");
}
return 0;
}