题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1079
解题思路:
P表示先手必胜,N表示先手必败。
当前能够转移到任意一种必败局面的为P
否则为N
剩下就是对年月日月份各种恶心的判断了
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
#define for0(i,a,b) for (int i=a;i<b;i++)
#define for1(i,a,b) for (int i=a;i<=b;i++)
char np[110][13][32];///i从0开始,到101,i+1900=真实年份
///j从1~12
///k从1~31
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}};
bool runnian(int x)
{
x = x+1900;
return ((x%100!=0 && x%4==0) || (x%400==0) );
}
void prework()
{
np[101][11][4] = 'N';
for (int i=101;i>=0;i--){
bool r = runnian(i);
for (int j=(i==101)?11:12;j>=1;j--){
for (int k=(i==101&&j==11)?3:mon[r][j];k>=1;k--){
int day1 = (k==mon[r][j])? 1:k+1;
int month1 = j + (day1==1);
if (month1==13) month1=1;
int year1 = (day1==1 && month1==1)? i+1:i;
///判断下一个月是否存在这一天
int day2 = k;
int month2 = (j==12)? 1:j+1;
int year2 = (month2==1)? i+1:i;
if (mon[runnian(year2)][month2]>=k && (year2<101 ||(year2==101 && year2<=11))){///这两天都可以取到
if (np[year1][month1][day1]=='N'||np[year2][month2][day2]=='N') np[i][j][k] = 'P';
else np[i][j][k] = 'N';
}
else {///只能取下一天
if (np[year1][month1][day1]=='N') np[i][j][k] = 'P';
else np[i][j][k] = 'N';
}
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--){
int y,m,d;
scanf("%d %d %d",&y,&m,&d);
if (np[y-1900][m][d]=='P') printf("YES\n");
else printf("NO\n");
}
return 0;
}