当前位置: 代码迷 >> 综合 >> HDU 1079 Calendar Game(博弈SG函数 || 奇偶找规律)
  详细解决方案

HDU 1079 Calendar Game(博弈SG函数 || 奇偶找规律)

热度:65   发布时间:2024-03-07 07:54:16.0

题意:
从当前日期,在他/她转的玩家可以移动到下一个历日或下月的同一天。当在之后的一个月中没有在同一天,播放器只能移动到下一个的日历日期。例如,从1924年12月19日,你可以移动到1924年12月20日,下一个日期,或一月19日,1925年,在同一天在下个月。然而,2001年1月31日,你可以只移动2001年2月1日,因为2001年2月31日是无效的。一个球员赢得比赛时,他/她到底到达的日期2001年11月4日。如果一个玩家移动到日期2001年11月4号之后,他/她输了比赛。

思路:
(2001 , 11 , 4)是个必败点,能到(2001, 11 , 4)的是必胜点,由时间从后向前推。

最后若输入的sg[] = 0即为必败点,输出 NO

#include<iostream>
#include<string.h>
using namespace std;
int sg[500][20][40];
int day[400];
int mm[15]={
    0,31,28,31,30,31,30,31,31,30,31,30,31};int g(int y , int m , int d)
{
    if(sg[y][m][d]!=-1) return sg[y][m][d];int flag=0;if(y>101) return sg[y][m][d]=0;if(m==2 && d==day[y] || m<12 && mm[m]==d && mm[m+1]>=d){
    int a=g(y,m+1,d) , b=g(y,m+1,1);if(a==0 || b==0) return sg[y][m][d]=1;else if(a && b)  return sg[y][m][d]=0;}else if(m<12 && mm[m]==d && mm[m+1]<d){
     int a=g(y,m+1,1); if(a==0)  return sg[y][m][d]=1;else return sg[y][m][d]=0;}else if(m==2 && d<day[y] || m<12 && d<mm[m] || m==12 && d<mm[12]){
     //cout<<"**************"<<endl; int a=g(y,m,d+1) , b=g(y , m+1 , d);// cout<<"a= "<<a<<" b= "<<b<<endl;if(a==0 || b==0 ) return sg[y][m][d]=1;else if(a && b) return sg[y][m][d]=0;}else if(m==12 && d==mm[12]){
    int a=g(y+1 ,1 ,1) , b=g(y+1 ,1, d);if(a==0 || b==0) return sg[y][m][d]=1;else if(a && b) return sg[y][m][d]=0;}
}int main()
{
    int y,m,d;int t;memset(sg,-1,sizeof(sg));for(int i=1900;i<=2001;i++)if(i%4==0&&i%100!=0 || i%400==0) day[i-1900+1]=29; else day[i-1900+1]=28;  sg[101][11][4]=0;for(int i=5;i<=mm[11];i++) sg[101][11][i]=1;for(int i=1;i<=mm[12];i++) sg[101][12][i]=1;scanf("%d",&t);while(t--){
    scanf("%d%d%d",&y,&m,&d);y-=1900; g(y,m,d);// cout<<"**= "<<sg[101][11][4]<<" "<<sg[101][11][3]<<endl;if(sg[y][m][d]==1) printf("YES\n");else printf("NO\n");}return 0;
}

找规律,不管是月份加一,还是日期加一,都改变了奇偶性,只有两个特殊日期9月30日,和11月30日例外(不管该年是否为润年,2月28\ 29同样一步都会发生正常奇偶变化)。

那么目标日期是11月4日,为奇数。初始日期如果为偶数的话,先者必胜。

考虑特殊是日期,两个特殊日期本来为奇数,可以做到移动一步还是奇数,那么必胜点与必败点发生变化。

那么会不会在中途经过这两个日期呢。

如果本来为偶数,如果经过特殊日期就会改变奇偶,从必胜到必败。作为先手,不会主动进入特殊日期,而后者不可能从奇数依旧到达特殊日期的奇数。

如果本来为奇数,同样先手想赢,但是不可能进入特殊日期。保持奇偶性交替变化。

这样一来只可能是初始为特殊日期,否则中途不可能出现特殊日期


#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    int y,m,d , t;cin>>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;
}
  相关解决方案