题目链接:点击查看
题目大意:给出一个日期,两个人轮流按照规则操作,具体规则如下:
- 每次可以增加一天
- 每次可以增加一个月到下一个月的当天
首先到达2001年11月4日的人获胜,问谁能获胜
题目分析:因为是从1900年1月1日开始的,最多只跨越了100年,也就是100*365天,大概也就1e5的分支,我们可以直接用dfs进行sg打表,每一次至多有两个分支,可以用两个if套上好多个if else就好了。。这样的话时间复杂度我不太会算,但因为用了sg打表,也相当于是记忆化搜索了,避免了重复分支的多次调用,所以交上去之后15毫秒就过了,还要吐槽一点,我的笔记本太不给力了。。在本地T掉了,本来很失望的交上去却A掉了,emmm
最后再感谢zx学长的思路,直接上代码了:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int N=4e5+100;
int sg[2020][15][35];//sg函数,类似于记忆化搜索
const 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 is_year(int year)//判断是否为闰年
{
if(year%4==0&&year%100!=0||year%400==0)
return true;
return false;
}
bool check(int a,int b,int c)//判断是否越界
{
if(a>2001||a==2001&&b>11||a==2001&&b==11&&c>4)
return false;
return true;
}
bool dfs(int a,int b,int c)//记忆化搜索
{
if(sg[a][b][c]!=-1)
return sg[a][b][c];
if(a==2001&&b==11&&c==4)
return sg[a][b][c]=false;
int pos=is_year(a);
if(c<mon[pos][b]&&check(a,b,c+1))//下一天
{
if(!dfs(a,b,c+1))
return sg[a][b][c]=true;
}
else if(c==mon[pos][b]&&b!=12&&check(a,b+1,1))//跨月不跨年
{
if(!dfs(a,b+1,1))
return sg[a][b][c]=true;
}
else if(c==mon[pos][b]&&b==12&&check(a+1,1,1))//跨年
{
if(!dfs(a+1,1,1))
return sg[a][b][c]=true;
}
if(b<12)//下一个月的同一天
{
if(c<=mon[pos][b+1])//确保下一个月中有这一天
if(check(a,b+1,c))
if(!dfs(a,b+1,c))
return sg[a][b][c]=true;
}
else if(b==12)//跨年
{
if(check(a+1,1,c))//12月和1月都是31天,所以不用特判
if(!dfs(a+1,1,c))
return sg[a][b][c]=true;
}
return sg[a][b][c]=false;
}
int main()
{
// freopen("input.txt","r",stdin);
memset(sg,-1,sizeof(sg));
int w;
cin>>w;
while(w--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(dfs(a,b,c))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}