(找规律+模拟)
题意:首先定义lucky-week是指:这天是周一而且是这个月的1,11,21号。给你t组测试样例,每组给出一行y,m,d,n,前三个是年月日,而且是满足lucky-week的第一个日期,要你输出你从这天开始第n个幸运周的日期。
题解:正常暴力做法被n限制了,那我们应该将n从1e9降下来,通过找到lucky-week关于年的循环规律,这里可以从电脑右下角的日历知道2001年的1月1号是lucky-week,而且考虑到闰年平年会有天数的差异导致答案的误差,我们我取最小避免平年闰年误差的值400年为周期,试着打一波从2001年到2401年的表可以发现,2401年的1月1日也是lucky-week,同时得到这400年中有2058个lucky-week(这里是不包括第2401年的),为了保险我们还可以打一波2001年到6001年的表,发现有20580个lucky-week(那就稳了),剩下的就是代码模拟了。
代码如下:
#include<cstdio> #include<algorithm> #include<vector> #include<queue> #include<string> #include<cstring> #include<iostream> using namespace std; #define ll long long const int maxn = 1e5 + 500; int mon[15] = { 0,31,29,31,30,31,30,31,31,30,31,30,31 }; bool ok(int y) {//判断平年闰年 if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0)) return true; return false; } void fun() {//打表找规律与判断答案是否正确 int s = 2001, t = 2401; int sum = 0, cnt = 0; for (int i = s; i < t; i++) { if (ok(i)) mon[2] = 29; else mon[2] = 28; for(int j=1;j<=12;j++) for (int k = 1; k <= mon[j]; k++) { sum++; if ((k == 1 || k == 11 || k == 21) && sum % 7 == 1) { cnt++; //cout << cnt << " " << i << " " << j << " " << k << endl; } } } cout << cnt << endl; } int main(){ //fun(); int t; scanf("%d", &t); while (t--) { int y, m, d, n; scanf("%d%d%d%d", &y, &m, &d, &n); y += (n / 2058) * 400; n %= 2058; int i, j, k,sum=0,cnt=0; if (cnt == n) { printf("%d %d %d\n", y, m, d); continue; } if (ok(y)) mon[2] = 29; else mon[2] = 28; for (k = d; k <= mon[m]; k++) {//先把当前月的天数处理了 sum++; if ((k == 1 || k == 11 || k == 21) && sum % 7 == 1) cnt++; if (cnt == n)break; } if (cnt == n) { printf("%d %d %d\n", y, m, k); continue; } for (j = m + 1; j <= 12; j++) {//再把当前年的月处理了 for (k = 1; k <= mon[j]; k++) { sum++; if ((k == 1 || k == 11 || k == 21) && sum % 7 == 1) cnt++; if (cnt == n)break; } if (cnt == n)break; } if (cnt == n) { printf("%d %d %d\n", y, j, k); continue; } for (i = y+1; ; i++) {//最后对年处理即一定能获得答案 if (ok(i)) mon[2] = 29; else mon[2] = 28; for (j = 1; j <= 12; j++) { for (k = 1; k <= mon[j]; k++) { sum++; if ((k == 1 || k == 11 || k == 21) && sum % 7 == 1) cnt++; if (cnt == n)break; } if (cnt == n)break; } if (cnt == n)break; } if (cnt == n) printf("%d %d %d\n", i, j, k); } return 0; }