Gym 101522D Distribution of Days【模拟】

博客内容介绍了如何使用泰勒公式计算从指定起始年份到结束年份,日期在不同星期出现的次数。通过考虑闰年和非闰年的天数差异,确定400年为一个循环周期,并预处理400年内的日期分布,然后计算给定年份范围内包含的400年周期数量及剩余天数对应的星期分布。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出起始年份st和结束年份ed,求给的日期,在这些年份中,分别是星期一~星期日几次。

思路:首先,根据泰勒公式算出1583.1.1是星期六(数据范围起始)。然后,由于闰年是400年一个循环,考虑到400年里,有97个闰年,不是闰年的年份有365天,365%7=1,也就是说不是闰年的时候每年的星期几的循环都推移一天,然后闰年还要多一天,也就是说要多400+97个推移量,497%7=0,也就是说400年是一个循环周期。那么只要先预处理出1583.1.1开始的400年里,题目给的这个日子,在每个星期x出现了几次,然后再把给的st和ed,算出有多少个400年循环,多出来的部分就找它对应的一开始的400年里哪一个即可。

代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
int days[13] = { 0, 31, 28 ,31 ,30 ,31 ,30 ,31 ,31 ,30 ,31 ,30 ,31 };

int q, st, ed, day, month, gi[8], ans[404];

bool isleap(int year)
{
	return (year % 400 == 0) || ((year % 4 == 0) && (year % 100));
}

int cal(int yy, int mm, int dd)
{
	int sum = 0;
	for (int i = 1; i < mm; i++)
	{
		sum += days[i];
		if (isleap(yy) && i == 2)
			sum++;
	}
	return sum+dd-1;
}

void cycle(int mm,int dd)
{
	int cnt=1,now = 6;//1583/1/1是星期六
	for (int i = 1583; i <= 1583 + 399; i++)
	{
		if (mm == 2 && dd == 29 && !isleap(i))
		{
			ans[cnt++] = 0;
		}
		else
		{
			ans[cnt++] = (cal(i, mm, dd) + now - 1) % 7 + 1;
		}
		if (isleap(i))
			now = (now + 366 - 1) % 7 + 1;
		else
			now = (now + 365 - 1) % 7 + 1;
	}
}


int main()
{
	scanf("%d", &q);
	while (q--)
	{
		memset(ans, 0, sizeof(ans));
		memset(gi, 0, sizeof(gi));
		scanf("%d %d %d %d", &st, &ed, &month, &day);
		cycle(month, day);
		int numed = (ed-1583 + 1) / 400;
		int numst = (st - 1583) / 400;
		for (int i = 1; i <= 400; i++)
		{
			gi[ans[i]] += (numed - numst);
		}
		int mped = ed - 1583 + 1 - numed * 400;
		int mpst = st - 1583 - numst * 400;
		for (int i = 1; i <= mpst; i++)
		{
			gi[ans[i]]--;
		}
		for (int i = 1; i <= mped; i++)
		{
			gi[ans[i]]++;
		}
		printf("%d", gi[7]);
		for (int i = 1; i <= 6; i++)
		{
			printf(" %d", gi[i]);
		}
		puts("");
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值