ZOJ 3939 The Lucky Week

题目链接:http://icpc.moe/onlinejudge/showProblem.do?problemId=5711

此题是浙江省第13届省赛的D题,比赛的时候小编一开始开的就是这个题,因为自己也有算天数差的模板,想也没想直接粘过来用,不管是怎么算都是TLE,后来才发现10^9的数据使肯定要爆的,必须得着周期才能算出来,在天数月份年数平闰年和星期数总体的周期是400(可能有人要问小编为什么加上星期数的周期还是400呢?平闰年的总体周期为400不难理解,但是如果你去计算你会发现每过400年的天数刚刚好也是7的倍数,这个当时在比赛的时候小编也专门开了一个草稿件去计算过,不懂得同学也可以直接去试试),因为我们的时间最小只能达到1753,所以我们先预处理1753的后门400年的情况,这样我们就可以再对应到我们算的那个时间,就可以处理出这个时间。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
struct point
{
    int year, month, day;
    int cnt;
    point (int year = 0, int month = 0, int day = 0, int cnt = 0): year(year), month(month), day(day), cnt(cnt){}
};
point a[10000];
int n;
int cnt;
int d1[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int d2[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool check(int x)
{
    if (x % 400 == 0 || (x % 4 == 0 && x % 100 != 0)) return true;
    return false;
}
void init()
{
    cnt = 1;
    int day = 1;
    for (int i = 1753; i <= 1753 + 399; i++)
	{
        bool flag = false;
        flag = check(i);
        for (int j = 1; j <= 12; j++){
            int tmp = (flag == 1 ? d2[j] : d1[j]);
            while (day <= tmp){
                if (day == 1 || day == 11 || day == 21)
				{
                    a[cnt] = point(i, j, day, cnt);
                    cnt++;
                }
                day += 7;
            }
            day -= tmp;
        }
    }
}
int main()
{
    init();
    cnt--;
    int t;
    scanf("%d", &t);
    while (t--){
        int y, m, d;
        scanf("%d%d%d", &y, &m ,&d);
        int n;
        scanf("%d", &n);
        n--;
        int ind = n / cnt;
        int tmp = n - ind * cnt;
        int mid = 0;
        while (y >= 1753 + 400)
		{
            y -= 400;
            mid++;
        }
        //printf("y = %d mid = %d tmp = %d\n", y, mid, tmp);
        ll t1 = 0, t2 = 0, t3 = 0;
        for (int i = 1; i <= cnt; i++){
            if (y == a[i].year && m == a[i].month && d == a[i].day){
                int g = i;
                g += tmp;
                while (g > cnt){
                    g -= cnt;
                    mid++;
                }
                t1 = (ll)a[g].year + (ll)(mid + ind) * 400;
                t2 = (ll)a[g].month;
                t3 = (ll)a[g].day;
                break;
            }
        }
        printf("%lld %lld %lld\n", t1, t2, t3);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值