题解 - P 7075 \mathrm{P7075} P7075
题目意思
S o l \mathrm{Sol} Sol
给一种二分的做法?
我们考虑先做 公元前 4713 ∼ 1 4713 \sim 1 4713∼1 年,我们预处理经过整 x x x 年需要几天。那么我们可以快速算出 n n n 天是在哪一年?
找到那一年我们只要 12 个月份依次模拟一遍即可。这样已经可以得到 40 40 40 分。
然后我们考虑公园 $1 \sim 10^9 $ 年。我们考虑二分 n n n 天后在哪一年。我们首先要从公元 1 1 1 年开始二分,所以 n n n 要减去 1721424 。二分如何判定?假设当前年为 y e a r year year。
如果 y e a r ≤ 1582 year\leq 1582 year≤1582 那么闰年个数即为 y e a r 4 \frac{year}{4} 4year,那么到 y e a r year year 年的天数为: 365 × y e a r + ( y e a r 4 ) 365\times year+(\frac{year}{4}) 365×year+(4year)
否则稍微容斥一下得到闰年个数为: g s = 1582 4 + y e a r 4 − 1581 4 + y e a r 400 − 1581 4 − y e a r 100 + 1581 4 gs=\frac{1582}{4}+\frac{year}{4}-\frac{1581}{4}+\frac{year}{400}-\frac{1581}{4}-\frac{year}{100}+\frac{1581}{4} gs=41582+4year−41581+400year−41581−100year+41581,
那么到 y e a r year year 年的天数为: 365 × y e a r + g s − 10 365\times year+gs-10 365×year+gs−10 减去 10 10 10 是因为 1582 1582 1582 年有 10 10 10 天是要去掉的。
最后我们只要再枚举 12 12 12 个月份即可,注意细节!!
时间复杂度 O ( q × log ( 1 0 9 ) + q × 12 ) O(q\times \log(10^9)+q\times 12) O(q×log(109)+q×12)
C o d e \mathrm{Code} Code
#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,a,b) for ( int i=(a);i>=(b);i-- )
#define int long long
using namespace std;
inline int read()
{
int x=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10ll+(ch^48),ch=getchar();
return x;
}
int Q,n,fl,day[15],sum[3000005],sum1[3000005],sumt[3000005];
inline void first_step()
{
int x=upper_bound(sum1+1,sum1+4714,n)-sum1-1;
int year=4713-x;
n-=sum1[x];
if(!n)
{
if(!year) printf("%d %d %d\n",1,1,year+1);
else printf("%d %d %d BC\n",1,1,year);
}
else
{
For(j,1,12)
{
if(fl) break;
int Day=28;
if(j!=2) Day=day[j];
else Day=((year-1)%4==0)?29:28;
if(n>Day) n-=Day;
else
{
fl=1;
if(n+1<=Day) printf("%d %d %d BC\n",n+1,j,year);
else if(j!=12) printf("%d %d %d BC\n",1,j+1,year);
else
{
if(year-1!=0) printf("%d %d %d BC\n",1,1,year);
else printf("%d %d %d\n",1,1,1);
}
n=0;
}
}
}
}
inline void third_step()
{
int l=1,r=1e9,x=0;
while(l<=r)
{
int mid=l+r>>1,tot_year=365*mid,rn_gs=0;
if(mid>=1582) tot_year-=10,rn_gs=(1581ll/4ll)+(mid/4ll)-(1581ll/4ll)+(mid/400ll)-(1581ll/400ll)-(mid/100ll)+(1581ll/100ll);
else rn_gs=mid/4ll;
tot_year+=rn_gs;
if(tot_year<=n) l=mid+1,x=mid;
else r=mid-1;
}
int year=x+1;
if(year<=1582) n-=(x*365+(x/4ll));
else n-=(x*365+(1582ll/4ll)+(x/4ll)-(1581ll/4ll)+(x/400ll)-(1581ll/400ll)-(x/100ll)+(1581ll/100ll)-10);
if(!n) printf("%d %d %d\n",1,1,year);
else
{
For(j,1,12)
{
if(fl) break;
int Day=28;
if(j!=2) Day=day[j];
else
{
if(year<=1582&&j<=10) Day=(year%4==0)?29:28;
else if(year%400==0||(year%4==0&&year%100!=0)) Day=29;
}
if(year==1582&&j==10)
{
if(n<=3) printf("%d %d %d\n",n+1,10,1582),fl=1,n=0;
else Day-=10;
}
if(n>=Day) n-=Day;
else if(!fl)
{
fl=1;
if(n+1<=Day)
{
if(year==1582&&j==10) printf("%d %d %d\n",n+11,j,year);
else printf("%d %d %d\n",n+1,j,year);
}
else if(j!=12) printf("%d %d %d\n",1,j+1,year);
else printf("%d %d %d\n",1,1,year+1);
n=0;
}
}
}
}
signed main()
{
Dow(i,4713,1) sum1[4713-i+1]=sum1[4713-i]+365+((i-1)%4==0);
Q=read();
day[1]=day[3]=day[5]=day[7]=day[8]=day[10]=day[12]=31,day[4]=day[6]=day[9]=day[11]=30;
for (;Q--;)
{
fl=0;
n=read();
if(n<=1721424) first_step();
else n-=1721424,third_step();
}
return 0;
}