A - Calendar Game HDU - 1079(博弈?逆推?)

分析

  • 题意
  1. 给我们一个日期 y 年、m 月、d 天,

  2. 我们可以对这个日期进行两个操作,

    1. 将 这个日期的天数 + 1,形成一个新的日期,
    2. 将 这个日期的月份 + 1,形成一个新的日期,如果这个不存在 y 年 m+1 月、d 日不存在的话,那么这个操作就不可以进行
  3. 先在两个极聪明的玩家,轮流进行前面两个操作中的一个,谁先将 所给的日期转移到 2001 年 11 月 4 日及之后的日期之后的的那个玩家获胜,

  • 思路
  1. 本题其实就是一个,就是一个简单的博弈题,只不过 需要特别判断是不是闰年,影响了题目的复杂度,
  2. 本题的主要的思路就是,从结局的 P/N 状态(后置节点),来逆推 后置节点的父节点,P/N 态,逆推的时候根据:
    1. 如果当前节点的所有后置节点都是 N 态的话,那么当前节点就是 P 态,
    2. 如果当前节点的所有后置节点只要有个事 P 态的话,那么当前节点就是 N 态,
  3. 其实这个逆推的过程像是 dp 求解答案一样,
  4. 思路是这样但是我们光考虑 平、闰年的时候,判断条件就很复杂了,这个时候我们在 dp 数组的时候有个简化技巧,可以将所有 dp 中的所有元素初始化为 2,为什么是 2?,因为 N 态用 1 表示、P 态用 0 表示,所以用 2,而且我们 dp 的转移方程使用 max 来取最优值的,所以 2 一定不回影响,P、N 态,这样在转移的时候就不用考虑,后置节点所代表的那一天存在不存在,即使不存在也不影响,状态转移方程的取值,,
  5. 剩下的直接看代码把。。。

代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <bitset>
#include <vector>
#include <stack>
#include <map>
/* #include <unordered_map> */
#include <sstream>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<int, int>
#define m_p make_pair
#define INF 0x3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(int i = (ll)(e); i >= (ll)(s); i --)
#define sc scanf
#define pr printf
#define sd(a) scanf("%d", &a)
#define ss(a) scanf("%s", a)
using namespace std;

int mon[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int dp[2005][15][35];

int main()
{

    /* fre(); */

    fill(dp[0][0], dp[0][0] + 2005*15*35, 2);
    dp[2001][11][4] = 0;
    dp[2001][11][3] = 1;
    dp[2001][11][2] = 0;
    dp[2001][11][1] = 1;

    for(int y = 2001; y >= 1900; y --)
    {
        if(y == 2001)
        {
            if((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) mon[2] ++;
            for(int m = 10; m >= 1; m --)
            {
                for(int d = mon[m]; d >= 1; d --)
                {
                    int td = d + 1, tm = m, ty = y;
                    if(td > mon[m]) td = 1, tm ++;
                    if(tm > 12) tm = 1, ty ++;

                    int tdd = d, tmm = m + 1, tyy = y;
                    if(tmm > 12) tmm = 1, tyy ++;

                    dp[y][m][d] = min(dp[ty][tm][td], dp[tyy][tmm][tdd]);
                    dp[y][m][d] ^= 1;
                }
            }
            if((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) mon[2] --;
        }
        else
        {
            if((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) mon[2] ++;
            for(int m = 12; m >= 1; m --)
            {
                for(int d = mon[m]; d >= 1; d --)
                {
                    int td = d + 1, tm = m, ty = y;
                    if(td > mon[m]) td = 1, tm ++;
                    if(tm > 12) tm = 1, ty ++;

                    int tdd = d, tmm = m + 1, tyy = y;
                    if(tmm > 12) tmm = 1, tyy ++;

                    dp[y][m][d] = min(dp[ty][tm][td], dp[tyy][tmm][tdd]);
                    dp[y][m][d] ^= 1;
                }
            }
            if((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) mon[2] --;
        }
    }

    int T; sd(T);
    while(T --)
    {
        int y, m, d;          
        sc("%d %d %d", &y, &m, &d);
        if(dp[y][m][d])
            pr("YES\n");
        else
            pr("NO\n");
    }


    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值