当时考场上因为这个炸掉,一年后回来复仇。

这里提供一个与大多数人不一样的做法。

首先考虑一个简单一些的问题,怎么应付单个询问?

不难想到,我们对于一个日期,让他从 \(-4713\) 年 \(1\) 月 \(1\) 日开始,然后一年一年地加,年加不了了加月,月加不了了加日。这样很容易做,具体的细节可以看代码实现。这样就拿下了 \(50pts\)。

但是肯定不能满足于这 \(50\) 分。对于数据过大造成的TLE,我们考虑扩展我们的做法。实际上,优化的本质是重复利用之前已经求过的东西。然后可以想到从每个询问入手。可以自己先思考一下再往下看。

我们可以考虑将询问离线然后排序,每次将上一次求出的答案为起始的日期,然后重复较为暴力的算法。但是由于有的月份的上限比别的月份高,又或者 \(1582\) 年这种比较特殊的日子,我们不能直接跑暴力的操作。我们需要把起始日期再转换为 \(n\) 年 \(1\) 月 \(1\) 日 这种形式的日期,再跑暴力。这里面有一些的细节,可以自己先尝试写,再看具体代码实现。(如我的实现有问题可以私信提醒我一下,谢谢!)

发现这么写得到了 \(90pts\) 的好成绩,但是就是没切,有些许难受。没关系,我们继续优化。我们不难发现对于在 \(1852\) 年之后的日子,是满足连续 \(400\) 年的总天数是一定的,可以自己尝试算一下有多少天。

具体就是 \(146097\) 天,算法就是 \(400\times 365+100-4+1\) ,\(400\) 天里 \(100\) 个 \(4\) 的倍数,\(4\) 个 \(100\) 的倍数,\(1\) 个 \(400\) 的倍数。

然后我们在暴力操作里面在一年一年加前面加上 \(400\) 年 \(400\) 年地加,就可以愉快的 \(AC\) 了!

Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define filein(a) freopen(#a".in","r",stdin)
#define fileot(a) freopen(#a".out","w",stdout)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
return s*f;
}//经典快读
inline ll read_ll(){
ll s=0;int f=1;char ch=getchar();
while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
return s*f;
}//快读long long版
inline void write(int x,char g){
static char ch[30],top;
top=0;if(x<0) {putchar('-');x=-x;}
do{ch[++top]=x-x/10*10;} while(x/=10);
do{putchar(ch[top--]+'0');} while(top);
if(g!=0) putchar(g);
}//经典快写
inline void write_st(short x,char g){
static char ch[30],top;
top=0;if(x<0) {putchar('-');x=-x;}
do{ch[++top]=x-x/10*10;} while(x/=10);
do{putchar(ch[top--]+'0');} while(top);
if(g!=0) putchar(g);
}//快写short版
int mt[12+3]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int yt[2+3]={365,366};
inline bool isR(int x){
if(x<0) return !((x+1)%4);
if(x<=1582) return !(x%4);
return ((!(x%4) and x%100) or !(x%400) );
}//判断是否为闰年
inline short adm(short x,int y){
if(y!=1582) return 0;
if(x==10) return -10;
return 0;
}//用来处理1582
inline short ady(int x){
if(x==1582) return -10;
return 0;
}//同上
struct ques{
int id;ll x;
inline friend bool operator<(ques x,ques y){
return x.x<y.x;
}
}q[(int)1e5+3];
int ay[(int)1e5+3];short am[(int)1e5+3],ad[(int)1e5+3];
int ckt1;
inline void ck1() {ckt1=clock();}
inline void ck2() {printf("%dms\n",clock()-ckt1);}
//这个是测速用的,可以忽略
int main(){
//filein(a);fileot(a);
int Q=read();
for(int i=1;i<=Q;++i){
q[i].x=read_ll();
q[i].id=i;
}
sort(q+1,q+1+Q);//操作离线
for(int ss=1;ss<=Q;++ss){
ll x=q[ss].x;
int y=-4713;short m=1,d=1;
if(ss!=1){//这个就是转换了
x-=q[ss-1].x;
y=ay[q[ss-1].id];
m=am[q[ss-1].id];
d=ad[q[ss-1].id];
//printf("%d %d %d %d\n",q[ss-1].id,d,m,y);
if(m!=1){
if(d!=1){
short kb=0;
if(d<5 and y==1582 and m==10){
kb+=10;
}//越过空的日期
if(x+kb>=mt[m]+((m==2)?isR(y):0)-d+1){
x+=kb;
x-=mt[m]+((m==2)?isR(y):0)-d+1;
d=1;++m;
if(m>12){
m-=12;
++y;
if(y==0) y=1;
}
if(m!=1){
bool flag=0;
for(short i=m;i<=12;++i){
if(x>=mt[i]+((i==2)?isR(y):0+adm(i,y) ) ){
x-=mt[i]+((i==2)?isR(y):0+adm(i,y) );
}else{
d+=x;
if(d-x<=4 and d>4 and y==1582 and m==10){
d+=10;
}//这边越过空的日期花费了能量,补回来,下面的重复操作同理
ay[q[ss].id]=y;
am[q[ss].id]=i;
ad[q[ss].id]=d;
flag=1;break;//发现在转换的过程中就找到答案了,就结束操作,下面的重复操作同理
}
}
if(flag) {continue;}
m=1;++y;
if(y==0) y=1;
}
}else{
d+=x;
if(d-x<=4 and d>4 and y==1582 and m==10){
d+=10;
}
ay[q[ss].id]=y;
am[q[ss].id]=m;
ad[q[ss].id]=d;
continue;
}
}else{
bool flag=0;
for(short i=m;i<=12;++i){
if(x>=mt[i]+((i==2)?isR(y):0+adm(i,y) ) ){
x-=mt[i]+((i==2)?isR(y):0+adm(i,y) );
}else{
d+=x;
if(d-x<=4 and d>4 and y==1582 and m==10){
d+=10;
}
ay[q[ss].id]=y;
am[q[ss].id]=i;
ad[q[ss].id]=d;
flag=1;break;
}
}
if(flag){continue;}
m=1;++y;
if(y==0) y=1;
}
}else if(d!=1){
short kb=0;
if(d<5 and y==1582 and m==10){
kb+=10;
}
if(x+kb>=mt[m]-d+1){
x+=kb;
x-=mt[m]-d+1;
d=1;++m;
bool flag=0;
for(short i=m;i<=12;++i){
if(x>=mt[i]+((i==2)?isR(y):0+adm(i,y) ) ){
x-=mt[i]+((i==2)?isR(y):0+adm(i,y) );
}else{
d+=x;
if(d-x<=4 and d>4 and y==1582 and m==10){
d+=10;
}
ay[q[ss].id]=y;
am[q[ss].id]=i;
ad[q[ss].id]=d;
flag=1;break;
}
}
if(flag) {continue;}
m=1;++y;
if(y==0) y=1;
}else{
d+=x;
if(d-x<=4 and d>4 and y==1582 and m==10){
d+=10;
}
ay[q[ss].id]=y;
am[q[ss].id]=m;
ad[q[ss].id]=d;
continue;
}
}
}
//printf(" %d %d %d %d\n",d,m,y,x);
bool Type=0;
if(y>1582)
while(x>=146100){
x-=146097;
y+=400;
}
while(x>=yt[Type=isR(y)]+ady(y) ){
x-=yt[Type]+ady(y);
++y;
if(y==0) y=1;
}
Type=isR(y);
while(x>=(mt[m]+((m==2)?Type:0+adm(m,y)) ) ){
x-=mt[m]+((m==2)?Type:0)+adm(m,y);
++m;
}
d+=x;
if(d-x<=4 and d>4 and y==1582 and m==10){
d+=10;
}
ay[q[ss].id]=y;
am[q[ss].id]=m;
ad[q[ss].id]=d;
}
for(int i=1;i<=Q;++i){
int y=ay[i];short m=am[i],d=ad[i];
if(y<0){
write_st(d,' ');write_st(m,' ');write(-y,' ');
printf("BC\n");
}else{
write_st(d,' ');write_st(m,' ');write(y,'\n');
}
}//输出
return 0;
}

题解 P7075 [CSP-S2020] 儒略日的更多相关文章

  1. 上午小测3 T1 括号序列 && luogu P5658 [CSP/S 2019 D1T2] 括号树 题解

    前 言: 一直很想写这道括号树..毕竟是在去年折磨了我4个小时的题.... 上午小测3 T1 括号序列 前言: 原来这题是个dp啊...这几天出了好几道dp,我都没看出来,我竟然折磨菜. 考试的时候先 ...

  2. [CSP模拟测试43、44]题解

    状态极差的两场.感觉现在自己的思维方式很是有问题. (但愿今天考试开始的一刻我不会看到H I J) A 考场上打了最短路+贪心,水了60. 然而正解其实比那30分贪心好想多了. 进行n次乘法后的结果一 ...

  3. 题解 nflsoj489 【六校联合训练 CSP #15】小D与随机

    题目链接 考虑枚举好点的集合.此时要考虑的问题是如何填入\(1\sim n\)这些数使得恰好我们枚举到的这些点是好点,即:求出有多少种合法的填数方案. \(1\)号点一定是好点.那么除\(1\)号点外 ...

  4. CCF CSP 201703-3 Markdown

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201703-3 Markdown 问题描述 Markdown 是一种很流行的轻量级标记语言(l ...

  5. CCF计算机职业资格认证考试题解

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF计算机职业资格认证考试题解 CCF计算机软件能力认证(简称CCF CSP认证)是CCF计算机职业资格认证系 ...

  6. CCF CSP 201312-3 最大的矩形

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201312-3 最大的矩形 问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i( ...

  7. CCF CSP 201609-3 炉石传说

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201609-3 炉石传说 问题描述 <炉石传说:魔兽英雄传>(Hearthston ...

  8. CCF CSP 201403-3 命令行选项

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201403-3 命令行选项 问题描述 请你写一个命令行分析程序,用以分析给定的命令行里包含哪些 ...

  9. CCF CSP 201709-4 通信网络

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201709-4 通信网络 问题描述 某国的军队由N个部门组成,为了提高安全性,部门之间建立了M ...

随机推荐

  1. Python使用递归绘制谢尔宾斯基三角形

    谢尔宾斯基三角形使用了三路递归算法,从一个大三角形开始,通过连接每一个边的中点,将大三角型分为四个三角形,然后忽略中间的三角形,依次对其余三个三角形执行上述操作. 运行效果: 源代码: 1 impor ...

  2. Java习题

    public class ClassTest{ String str = new String("hello"); char[] ch = {'a','b','c'}; publi ...

  3. Python中用函数实现代码的复用

    # Python中用函数实现代码复用 """ def funcname(paras): statements return [expression] 关于函数定义说明如下 ...

  4. Java类型转换详解

    Java类型转换详解 最近有同学问:自动类型转换老是记不住,到底是大转小,还是小转大 其实这个不用死记硬背,很好理解,我们拿 int 和 short 来举例: int 是 4 字节,也就是 32 bi ...

  5. numpy教程06---ndarray的进阶操作

    欢迎关注公众号[Python开发实战], 获取更多内容! 工具-numpy numpy是使用Python进行数据科学的基础库.numpy以一个强大的N维数组对象为中心,它还包含有用的线性代数,傅里叶变 ...

  6. 不用关闭重启cad及不用更改快捷方式或者版本号c#调试cad插件

    c#开发的cad插件需要重启cad才能进行调试,然而高版本的cad启动比较慢特别是一些古董电脑,而且cad有重启次数限制.针对不用重启cad调试已经有成熟的方案了,但是需要调试一次修改一次快捷方式或者 ...

  7. No package XXX available 解决方法

    当前yum源找不到所需包,安装epel源即可 yum install -y epel-release EPEL 的全称叫 Extra Packages for Enterprise Linux.EPE ...

  8. Java之万年历

    @(文章目录) 二.Java之万年历 2.1 要求 输入年份: 输入月份: 输出某年某月的日历. 2.2 思路 实现从控制台接收年和月,判断是否是闰年(判断是否是闰年:能被4整除但不能被100整除:或 ...

  9. vue 实现高德坐标转GPS坐标

    vue 实现高德坐标转GPS坐标 首先介绍一下常见的几种地图的坐标类型: WGS-84:这是一个国际标准,也就是GPS坐标(Google Earth.或者GPS模块采集的都是这个类型). GCJ-02 ...

  10. 【多线程与高并发原理篇:3_java内存模型】

    1. 概述 Java 内存模型即 Java Memory Model,简称 JMM.从抽象的角度来看,JMM 定义了线程和主内存之间的抽象关系,线程之间的共享变量存储在主内存中,每个线程都有一个私有的 ...