feat: 添加版本号比较功能并优化日期计算逻辑

实现版本号比较功能,新增 compare-version-numbers.cpp 文件。同时重构 P7075.cpp 中的日期计算逻辑,优化闰年判断和日期转换算法,提高代码可读性和准确性。
This commit is contained in:
Zengtudor 2025-09-23 15:51:07 +08:00
parent e4225e6f1a
commit f8b4831d7b
2 changed files with 248 additions and 28 deletions

View File

@ -1,37 +1,190 @@
#include <cstdint>
#include <iostream>
#include <istream>
#include <map>
using ll = int64_t;
#include <vector>
#include <numeric>
const ll af = 400*365+97;
const ll bf = 400*365+100;
// 使用 long long 防止在计算天数和年份时溢出
using ll = long long;
const ll l = 2299160;
// 公元后每月天数(非闰年)
const int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
struct Day{
ll d,m,y;
};
std::map<ll, Day> m;
static inline void solve(ll n){
if(n<=l){
}else{
// 预计算一些关键时间点的儒略日数值
// 公元 1 年 1 月 1 日对应的儒略日 (r)
const ll R_AD_START = 1721424; // (4713 - 1) * 365 + (4713 - 1) / 4 = 1721423. r=0 是第一天所以第1721424天是公元1年1月1日
// 公元 1582 年 10 月 5 日对应的儒略日
const ll R_GREGORIAN_START = 2299161; // 这是被删除的10天的第一天
// 判断公元后年份是否为儒略历闰年
bool is_julian_leap(ll year) {
return year % 4 == 0;
}
// 判断公元后年份是否为格里高利历闰年
bool is_gregorian_leap(ll year) {
return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
}
// 解决单个查询的函数
void solve() {
ll r;
std::cin >> r;
// 阶段一:处理公元前日期
if (r < R_AD_START) {
// 从公元前4713年开始
ll year = 4713;
// +1 是因为 r=0 是第一天
ll days_left = r + 1;
// 逐年减去天数来确定年份
while (true) {
bool is_bc_leap = (year % 4 == 1); // 公元前闰年规则
int year_days = 365 + (is_bc_leap ? 1 : 0);
if (days_left <= year_days) {
break; // 找到了年份
}
days_left -= year_days;
year--;
}
// 在年内确定月份和日期
int month = 1;
bool is_bc_leap = (year % 4 == 1);
while (true) {
int month_days = days_in_month[month];
if (month == 2 && is_bc_leap) {
month_days = 29;
}
if (days_left <= month_days) {
break; // 找到了月份
}
days_left -= month_days;
month++;
}
std::cout << days_left << " " << month << " " << year << " BC\n";
return;
}
// 如果 r >= R_AD_START说明是公元后日期
// 将 r 转换为相对于公元 1 年 1 月 1 日的天数
ll days_since_ad = r - R_AD_START + 1;
ll year = 1;
// 阶段二:处理儒略历的公元后时期 (直到 1582 年 10 月 4 日)
if (r < R_GREGORIAN_START) {
// 逐年逼近
while (true) {
int year_days = 365 + (is_julian_leap(year) ? 1 : 0);
if (days_since_ad <= year_days) {
break;
}
days_since_ad -= year_days;
year++;
}
// 年内确定月日
int month = 1;
while (true) {
int month_days = days_in_month[month];
if (month == 2 && is_julian_leap(year)) {
month_days = 29;
}
// 特殊处理 1582 年 10 月
if (year == 1582 && month == 10) {
// r < R_GREGORIAN_START 保证了日期在4号或之前
// 此时 days_since_ad 就是当月的日期
break;
}
if (days_since_ad <= month_days) {
break;
}
days_since_ad -= month_days;
month++;
}
std::cout << days_since_ad << " " << month << " " << year << "\n";
return;
}
// 阶段三:处理格里高利历时期 (1582 年 10 月 15 日及以后)
// 从 1582 年 10 月 15 日开始计算
days_since_ad = r - R_GREGORIAN_START + 1;
year = 1582;
int month = 10;
ll day = 15;
// 先减去 1582 年剩余的天数
ll remaining_days_1582 = 31 - 15 + 1 + 30 + 31; // 10, 11, 12 月
if (days_since_ad <= remaining_days_1582) {
days_since_ad += 14; // 补偿回15号之前的日子方便计算
while(true){
int month_days = days_in_month[month];
if(days_since_ad <= month_days){
day = days_since_ad;
break;
}
days_since_ad -= month_days;
month++;
}
std::cout << day << " " << month << " " << year << "\n";
return;
}
days_since_ad -= remaining_days_1582;
year = 1583;
// 格里高利历的400年周期天数400*365 + 97 = 146097
const ll GREGORIAN_CYCLE_DAYS = 146097;
ll num_cycles = days_since_ad / GREGORIAN_CYCLE_DAYS;
year += num_cycles * 400;
days_since_ad %= GREGORIAN_CYCLE_DAYS;
// 如果 days_since_ad 为 0, 说明是上一个周期的最后一天,需要回退
if (days_since_ad == 0) {
year -= 400;
// 一个周期正好是146097天所以回退后是这一大周期的最后一天
days_since_ad = GREGORIAN_CYCLE_DAYS;
}
// 在剩余的小于400年的周期内逐年确定年份
while (true) {
int year_days = 365 + (is_gregorian_leap(year) ? 1 : 0);
if (days_since_ad <= year_days) {
break;
}
days_since_ad -= year_days;
year++;
}
// 年内确定月日
month = 1;
while (true) {
int month_days = days_in_month[month];
if (month == 2 && is_gregorian_leap(year)) {
month_days = 29;
}
if (days_since_ad <= month_days) {
break;
}
days_since_ad -= month_days;
month++;
}
day = days_since_ad;
std::cout << day << " " << month << " " << year << "\n";
}
int main() {
std::iostream::sync_with_stdio(false);
std::cin.tie(nullptr);
// OI/ACM 风格的快速 IO
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
ll Q;
int Q;
std::cin >> Q;
while (Q--) {
ll r;
std::cin>>r;
solve(r);
solve();
}
return 0;
}

View File

@ -0,0 +1,67 @@
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
struct Version{
vector<int> v;
inline int operator[](int n)const{
if(n<v.size()){
return v[n];
}
return 0;
}
inline Version(const string &str){
int p=0;
for(int i=0;i<str.size();i++){
if(str[i]=='.'){
v.push_back(
atoi(str.substr(p,i-p).c_str())
);
p=i+1;
}
}
v.push_back(
atoi(str.substr(p).c_str())
);
for(auto i:v){
printf("%d ",i);
}
printf("\n");
}
inline bool operator<(const Version&other)const{
for(int i=0;i<max(v.size(),other.v.size());i++){
if((*this)[i]<other[i]){
return true;
}else if((*this)[i]>other[i]){
return false;
}
}
return false;
}
inline bool operator==(const Version&other)const{
for(int i=0;i<max(v.size(),other.v.size());i++){
if((*this)[i]!=other[i]){
return false;
}
}
return true;
}
};
inline int compareVersion(string version1, string version2) {
Version v1=version1;
Version v2=version2;
if(v1==v2)return 0;
return v1<v2?-1:1;
}
};
int main(){
}