题解 P7075 【儒略日(洛谷民间数据)】
给一种考场上最不用脑子也最不会写挂的做法吧(现场写加调1h左右,删了没有必要的行大概也就1k左右)
考虑二分年份
问题转化为了算
这里有一个trick就是我们先把公元前的年份往前平移一年,即把
那么则有 总天数=
对于闰年数量,首先先算4的倍数的年份数量
对于1600年后的整百年,贡献是
那就算完了,注意long long以及二分边界即可.
复杂度
给一个考场上的代码(删了调试语句)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline ll readll(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
const int dom[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int y=-4737,m=1,d=1;
int isRUN(int y){
if(y<=0){
y=-y;
return y%4==1;
}
if(y<=1582)return y%4==0;
return (y%400==0)||((y%4==0)&&(y%100!=0));
}
void getnxtday(){
d++;
if(y==1582&&m==10&&d==5)d=15;
if(d>dom[m]+(m==2&&isRUN(y)))m++,d=1;
if(m>12)y++,m=1;
}
ll checkday(int x){
ll day=1ll*(x+4712)*365;
if(x>1582)day-=10;
day+=1ll*(x+4712+3)/4;
if(x>=1600){
x-=1601;
day-=(ll)x/100ll;
day+=(ll)x/400ll;
}
return day;
}
int main(){
int T;
T=read();
while(T--){
y=0;m=d=1;
ll n=readll();
int l=-4712,r=1e9+1;
while(l<=r){
int mid=(l+r)/2;
if(checkday(mid)<=n){
y=mid;
l=mid+1;
}else r=mid-1;
}
n-=checkday(y);
if(y<=0)y--;
while(n--)getnxtday();
printf("%d %d ",d,m);
if(y<=0)printf("%d BC\n",-y);
else printf("%d\n",y);
}
return 0;
}