Edward, the headmaster of the Marjar University, is very busy every day and always forgets the date.
There was one day Edward suddenly found that if Monday was the 1st, 11th or 21st day of that month, he could remember the date clearly in that week. Therefore, he called such week "The Lucky Week".
But now Edward only remembers the date of his first Lucky Week because of the age-related memory loss, and he wants to know the date of the N-th Lucky Week. Can you help him?
There are multiple test cases. The first line of input is an integer T indicating the number of test cases. For each test case:
The only line contains four integers Y, M, D and N (1 ≤ N ≤ 109) indicating the date (Y: year, M: month, D: day) of the Monday of the first Lucky Week and the Edward's query N.
The Monday of the first Lucky Week is between 1st Jan, 1753 and 31st Dec, 9999 (inclusive).
For each case, print the date of the Monday of the N-th Lucky Week.
2 2016 4 11 2 2016 1 11 10
2016 7 11 2017 9 11Author: GAN, Tiansheng
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; } const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f; int casenum, casei; int mon[13] = { 0,31,0,31,30,31,30,31,31,30,31,30,31 }; struct date { int y, m, d; date(int y, int m, int d) :y(y), m(m), d(d) {} }; int tp[400][13][32]; //tp[y][m][d]表示如果y年m月d日是满足要求的日期,那么0年1月1日是星期几 int o[400][13][32]; //o[y][m][d]表示如果y年m月d日是满足要求的日期,那么这是其在相应起点下所对应的第几个满足要求的日期 vector<date>a[7]; //a[i][j]表示0年1月1日是星期i的条件下的第j个满足要求的日期 int nxt[7] = { 1,2,3,4,5,6,0 }; int sum[7]; //sum[i]表示0年1月1日是星期i的条件下,在400年范围内有几个满足要求的日期 bool leap(int y) { return y % 400 == 0 || y % 100 != 0 && y % 4 == 0; } void init() { for (int st = 0; st < 7; ++st) { int w = (st + 6) % 7; sum[st] = 0; for (int y = 0; y < 400; ++y) { mon[2] = leap(y) + 28; for (int m = 1; m <= 12; ++m) { for (int d = 1; d <= mon[m]; ++d) { w = nxt[w]; if ((d == 1 || d == 11 || d == 21) && w == 0) { tp[y][m][d] = st; o[y][m][d] = sum[st]++; a[st].push_back(date(y, m, d)); } } } } } } int main() { init(); scanf("%d", &casenum); for (casei = 1; casei <= casenum; ++casei) { int y, m, d, n; scanf("%d%d%d%d", &y, &m, &d, &n); int cir = y / 400; y %= 400; int typ = tp[y][m][d]; n += o[y][m][d] - 1; cir += n / sum[typ]; n %= sum[typ]; int yy = cir * 400 + a[typ][n].y; int mm = a[typ][n].m; int dd = a[typ][n].d; printf("%d %d %d\n", yy, mm, dd); } return 0; } /* 【题意】 我们定义幸运日为—— 1,星期1, 2,恰好是当前月份的1号,11号或21号。 现在给你 (1st Jan, 1753 and 31st Dec, 9999)范围内的某个日期, 把该日期作为第一个幸运日,问你第n(1e9范围)个星期日是几年几月几日 【类型】 前缀和预处理 暴力模拟 【分析】 没有告诉你数据组数。而且N如此之大,直接暴力要GG。 首先,对于日期天数,显然400年构成一个循环。 即400年前的几月几号星期几,现在同样是星期几。 于是我们直接枚举0年1月1日星期几,然后暴力处理400年的前缀和。 那么—— 对于当前的y年m月d日, 我们把y/400得到轮数(400年为一轮)偏移量, 把y%=400得到日期映射, 然后增加的n-1天,将(n-1)/sum转化为轮数的偏移量 用a[y][m][d]记录y年m月d日是400年内第几个幸运日,并+=(n-1)%sum 映射得到400年一轮下,轮数之外的偏移量。 具体参考代码。 【时间复杂度&&优化】 O(400*365) 一个优化是,我们可以只做400年的预处理。 (因为实际上400年就完成一轮循环,星期又重回原点了) */