HDU 1079 Calendar Game (博弈或暴搜)

题意:给定一个日期,然后 A 和 B 双方进行操作,谁先把日期变成2001年11月04日,将获胜,如果超过该日期,则输了,就两种操作。

第一种:变成下一天,比如现在是2001.11.3 变成 2001.11.4

第二种,变成下一个月的同一天,比如现在是2001.10.3 变成 2001.11.3,当然有可能是不成立的,比如2001.1.30 不能变成2001.2.30,因为2月没有30天。

析:因为题目中说了是从1990年到2001年,大约100年的时间,也就是400 * 100,完全可以存储下来,或者是直接暴力并且记忆化,这里就是要处理一些特殊情况,比如闰年,下一天跨年了,或者超过2001.11.4了等等,速度还挺快的。

这第二种解法才是正规的解法,要发现这两种情况的共同点,首先把月份和日份看成一个整体,或者是求和sum就好,因为 11+4 = 15,15 是奇数,那么如果开始的日期是偶数,就一定能够获胜,除非有一种日期从能偶数只能变成偶数,很遗憾,并没有这种日期,也就是只要日期是偶数就是一定能够获胜,下面有解释,当然前提是这两个人都足够聪明,那么是不是是奇数就不能胜了?答案不一定,下面慢慢分析,把日期分成三大类,

第一类,变成一个月的同一天,那么如果能变化的话,sum的奇偶性会发生变化,也就是奇变偶,偶变奇

第二类,就成下一天,对于这个仔细点会发现,sum不全是会变化,只有几个是特例,这第二类就是sum会变化的,

第三类,我们细分一下哪几个特例,也就是说下一天,sum不一定会发生变化的,首先就是 2 月 这个特殊的月份,先考虑不是闰年,那么 2 月就只有 28 天,2 + 28 是偶数,我们推理过如果 sum 是偶数,那么就一定能获胜,那么如果是闰年呢,那么 2 月有 29 天,那么是一个奇数,它的一天是 3.1,奇偶性变成了变化,所以不用考虑 2 月了,同理可以解决 4.30 虽然下一个日期是 5.1 也是偶数,但是它本身偶数,所以一定能获胜,6.30 也是,但是有两个特例也就满足这第三类的,9.30 和 11.30 这两个 sum 是奇数,但是它的下一天是是奇数,下一个月是偶数,也就是说奇偶性不一定不发生变化。但是这两个日期一定能获胜,为什么呢,因为当某个玩家到了 9.30 或者是 11.30 ,我们前面考虑过了如果日期是偶数,就能够获胜,所以它肯定是选择变成下一个日期,这样的话,对方就是奇数了,而下次我就是成偶数了。也就是说如果经过 9.30 或者是 11.30 那么奇偶就会发生翻转。那么这和我们前面说的偶数就一定能够获胜好像是矛盾啊,其实不然,因为每个人都是足够聪明的,能够获胜的那个玩家肯定要避免对方能够拿到这个日期,而且完全可以做到举个例子,  9.30 能够到达 9.30 的只有 9.29 或者是 8.30,那么只要 9.29 的变成下一个月,8.30 的变成下一天,就能够避免对方得到这两个日期,也就能够获胜了。同时如果给定一开始给定的就是 9.30 或 11.30 ,那么这个和虽然不是偶数,也是也能获胜,至少为什么,前面已经说了,经过这两个日期,聪明的玩家的可以把奇偶性翻转,并且以后可以避免让对方再得到这两个日期。

综上,如果先手想胜的话,只有二种情况,一种是日份和月份的和是偶数,第二种,就是开始日期就是 9.30 或者是 11.30。

两种不同的解法,代码差的可不是一点,但是思维量也不是同等的

代码如下:

首先先贴上 dfs 记忆化解决 SG 函数的代码

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#include <numeric>
#define debug() puts("++++")
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define sz size()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
//#define all 1,n,1
#define FOR(i,x,n)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.in", "r", stdin)
#define freopenw freopen("out.out", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e17;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1000 + 10;
const int maxm = 100 + 2;
const LL mod = 100000000;
const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1};
const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c) {
  return r >= 0 && r < n && c >= 0 && c < m;
}

bool isLeapYear(int x){
  if(x % 400 == 0)  return true;
  if(x % 100 == 0)  return false;
  if(x % 4 == 0)  return true;
  return false;
}

int nextDay(int x){
  int d = x % 100;  x /= 100;
  int m = x % 100;  x /= 100;
  int y = x;
  if(isLeapYear(y) ? monn[m] == d : mon[m] == d){
    d = 1; ++m;
    if(m > 12)  m = 1, ++y;
    return (y * 100 + m) * 100 + d;
  }
  return (y * 100 + m) * 100 + d + 1;
}

int nextMonth(int x){
  int d = x % 100;  x /= 100;
  int m = x % 100;  x /= 100;
  int y = x;
  if(m == 12)  return (y * 100 + 101) * 100 + d;
  if(m == 1 && d == 29)  return isLeapYear(y) ? (y * 100 + 2) * 100 + d : 0;
  if(m == 1 && d > 29)  return 0;
  if(mon[m+1] < d)  return 0;
  return (y * 100 + m + 1) * 100 + d;
}

map<int, bool> mp;
const int last_date = 20011104;

bool dfs(int x){
  if(mp.count(x))  return mp[x];
  bool &ans = mp[x];
  if(x == last_date)  return ans = false;
  int next = nextDay(x);
  if(!dfs(next))  return ans = true;
  if((next = nextMonth(x)) && next <= last_date && !dfs(next))  return ans = true;
  return ans = false;
}

int main(){
  int T;  cin >> T;
  int y, d;
  while(T-- && scanf("%d %d %d", &y, &m, &d) == 3){
    n = (y * 100 + m) * 100 + d;
    if(dfs(n))  puts("YES");
    else  puts("NO");
  }
  return 0;
}

  

下面是正解的代码

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#include <numeric>
#define debug() puts("++++")
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define sz size()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
//#define all 1,n,1
#define FOR(i,x,n)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.in", "r", stdin)
#define freopenw freopen("out.out", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e17;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1000 + 10;
const int maxm = 100 + 2;
const LL mod = 100000000;
const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1};
const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c) {
  return r >= 0 && r < n && c >= 0 && c < m;
}


int main(){
  int T;  cin >> T;
  while(T--){
    int y, d;
    scanf("%d %d %d", &y, &m, &d);
    if((m+d) % 2 == 0 || m == 9 && d == 30 || m == 11 && d == 30)  puts("YES");
    else  puts("NO");
  }
  return 0;
}

  

原文地址:https://www.cnblogs.com/dwtfukgv/p/8431914.html