题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1079
大意是两个人从1900年1月1日之后的某一天开始走,每次可以走到下一天或者下个月的这一天(如果存在的话),谁先走到2001年11月4日就获胜。学习完博弈后最先想到的办法是求PN状态,数据量比较大而且没有找到规律,于是就从后往前枚举了一下每天的PN态,存储在sg数组中,就过了。
这是代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stack>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
int sg[200][15][50];
int feb[200];
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int getsg(int y,int m,int d)
{
if(y>1000) y -= 1900;
if(sg[y][m][d] != -1){
return sg[y][m][d];
}
if(m==12){
if(d==31){
int a = getsg(y+1,1,1), b = getsg(y+1,1,d);
if(a && b) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
else{
int a = getsg(y,m,d+1), b = getsg(y+1,1,d);
if(a && b) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
}
else if(m==1){
if(d <= feb[y]){
int a = getsg(y,m,d+1), b = getsg(y,m+1,d);
if(a && b) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
else{
int a;
if(d==31) a = getsg(y,m+1,1);
else a = getsg(y,m,d+1);
if(a) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
}
else if(d <= days[m+1]){
if(d==days[m]){
int a = getsg(y,m+1,1), b = getsg(y,m+1,d);
if(a && b) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
else{
int a = getsg(y,m,d+1), b = getsg(y,m+1,d);
if(a && b) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
}
else if(d > days[m+1]){
if(d==days[m]){
int a = getsg(y,m+1,1);
if(a) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
else{
int a = getsg(y,m,d+1);
if(a) sg[y][m][d] = 0;
else sg[y][m][d] = 1;
}
}
else printf("******************include error at : %d %d %d\n",y+1900,m,d);
return sg[y][m][d];
}
bool isleap(int year)
{
if( (year%4==0 && year%100!=0) || year%400==0 ) return true;
return false;
}
int main()
{
int y, m, d;
for(int i=0;i<=101;i++){
if(isleap(1900+i)) feb[i] = 29;
else feb[i] = 28;
}
memset(sg,-1,sizeof(sg));
sg[101][11][4] = 0;
for(int i=5;i<=30;i++) sg[101][11][i] = 1;
for(int i=1;i<=31;i++) sg[101][12][i] = 1;
int cse;
cin>>cse;
while(cse--){
scanf("%d %d %d",&y,&m,&d);
int ans = getsg(y,m,d);
if(ans) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
之后看网上有人用了找规律的方法,发现正常操作都会改变奇偶性,只有9月30日和11月30日例外,但是没有看懂。。。如果是这样那代码就很短了~
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
int y,m,d , t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&y,&m,&d);
if((m+d)%2==0 || m==9 && d==30 || m==11 && d==30) printf("YES\n");
else printf("NO\n");
}
return 0;
}