【真题研究】CSP-S2020
[CSP-S2020] 儒略日
大模拟。
可以将时间分为 \(4\) 个部分:
- \(-4713.1.1\) 至 \(-1.12.31\)
- \(1.1.1\) 至 \(1582.10.4\)
- \(1582.10.5\) 至 \(1582.10.14\)
- \(1582.10.15\) 至无穷
大体可分为公元前(儒略历),公元后儒略历,公元后格里高利历。
如果 \(x\le 1721424\),说明是公元前儒略历,\(4\) 年一打包,其中 \(1\) 个闰年和 \(3\) 个平年,共 \(1461\) 天。然后按周期推年份。推完年份剩下的天数用来推月份,天数即可,注意判断闰年。
void bc(int x) {
int dY = x / zq1, i, op = 0; x %= zq1;
for (i = 0; i < 4; i++) {
if(i % 4 == 0 && x > 366) x -= 366;
else if(i % 4 != 0 && x > 365) x -= 365;
else break;
}
Y = 4713 - (dY * 4 + i);
if(x == 0) {
D = 31, M = 12;
Y++;
return ;
}
if(i == 0) op = 1;
for (i = 1; i <= 12; i++) {
int del = ((op && i == 2) ? Mth[i] + 1 : Mth[i]);
if(x > del) x -= del;
else break;
}
M = i;
D = x;
return ;
}
如果 \(1721424 < x \le 2299161\),说明是公元后儒略历,和公元前儒略历类似,不过多赘述。
void BBC(int x) {
int dY = x / zq1, i, op = 0; x %= zq1;
for (i = 1; i <= 4; i++) {
if(i % 4 == 0 && x > 366) x -= 366;
else if(i % 4 != 0 && x > 365) x -= 365;
else break;
}
Y = (dY * 4 + i);
if(x == 0) {
D = 31, M = 12;
Y--;
return ;
}
if(Y % 4 == 0) op = 1;
for (i = 1; i <= 12; i++) {
int del = ((op && i == 2) ? Mth[i] + 1 : Mth[i]);
if(x > del) x -= del;
else break;
}
M = i;
D = x;
return ;
}
然后是日期删除的部分,直接跳过\(1582.10.5\) 到 \(1582.10.15\) 日。然后进入到公元后格里高利历。由于 \(1582\) 年是从 \(10.15\) 开始的,所以要特判断掉这一年。到 \(1582.12.31\) 共 \(78\) 天。
if(x <= 78) {
if(x <= 17) {
M = 10, D = 15+x-1;
} else if(x <= 47) {
x -= 17;
M = 11, D = x;
} else {
x -= 47;
M = 12, D = x;
}
Y = 1582;
cout << D << ' ' << M << ' ' << Y << '\n';
return ;
}
然后按 \(400\) 年为一周期打包,一个周期有 \(97\) 个闰年和 \(303\) 个平年,共 \(97\times 366+303\times 365=146097\) 天。推完年份剩下的天数用来推月份,天数即可,注意判断闰年需要把 \(1582\) 年和包内的年份一起算上判断。
int dY = (x / y400), i, op = 0; x %= y400;
for (i = 1; i <= 400; i++) {
if(check(1582 + dY * 400 + i) && x > 366) x -= 366;
else if(!check(1582 + dY * 400 + i) && x > 365) x -= 365;
else break;
}
Y = 1582 + dY * 400 + i;
if(x == 0) {
M = 12, D = 31;
Y--;
goto ans2;
}
if(check(Y)) op = 1;
for (i = 1; i <= 12; i++) {
int del = ((op && i == 2) ? Mth[i] + 1 : Mth[i]);
if(x > del) x -= del;
else break;
}
M = i;
D = x;
ans2: cout << D << ' ' << M << ' ' << Y << '\n';
然后整合起来,分类讨论即可。
时间复杂度 \(O(q)\)。
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int Mth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int zq1 = 1461, BC = 1721424, k1582 = 577737, y400 = 146097;
int q, x, D, M, Y;
bool check(int x) {
if(x % 400 == 0) return 1;
if(x % 4 == 0 && x % 100 != 0) return 1;
return 0;
}
void BBC(int x) {
int dY = x / zq1, i, op = 0; x %= zq1;
for (i = 1; i <= 4; i++) {
if(i % 4 == 0 && x > 366) x -= 366;
else if(i % 4 != 0 && x > 365) x -= 365;
else break;
}
Y = (dY * 4 + i);
if(x == 0) {
D = 31, M = 12;
Y--;
return ;
}
if(Y % 4 == 0) op = 1;
for (i = 1; i <= 12; i++) {
int del = ((op && i == 2) ? Mth[i] + 1 : Mth[i]);
if(x > del) x -= del;
else break;
}
M = i;
D = x;
return ;
}
void bc(int x) {
int dY = x / zq1, i, op = 0; x %= zq1;
for (i = 0; i < 4; i++) {
if(i % 4 == 0 && x > 366) x -= 366;
else if(i % 4 != 0 && x > 365) x -= 365;
else break;
}
Y = 4713 - (dY * 4 + i);
if(x == 0) {
D = 31, M = 12;
Y++;
return ;
}
if(i == 0) op = 1;
for (i = 1; i <= 12; i++) {
int del = ((op && i == 2) ? Mth[i] + 1 : Mth[i]);
if(x > del) x -= del;
else break;
}
M = i;
D = x;
return ;
}
void solve() {
D = M = Y = 0;
cin >> x; x++;
if(x <= BC) {
bc(x);
cout << D << ' ' << M << ' ' << Y << " BC\n";
} else {
x -= BC;
if(x <= k1582) {
BBC(x);
cout << D << ' ' << M << ' ' << Y << '\n';
} else {
x -= k1582;
if(x <= 78) {
if(x <= 17) {
M = 10, D = 15+x-1;
} else if(x <= 47) {
x -= 17;
M = 11, D = x;
} else {
x -= 47;
M = 12, D = x;
}
Y = 1582;
cout << D << ' ' << M << ' ' << Y << '\n';
return ;
}
x -= 78;
int dY = (x / y400), i, op = 0; x %= y400;
for (i = 1; i <= 400; i++) {
if(check(1582 + dY * 400 + i) && x > 366) x -= 366;
else if(!check(1582 + dY * 400 + i) && x > 365) x -= 365;
else break;
}
Y = 1582 + dY * 400 + i;
if(x == 0) {
M = 12, D = 31;
Y--;
goto ans2;
}
if(check(Y)) op = 1;
for (i = 1; i <= 12; i++) {
int del = ((op && i == 2) ? Mth[i] + 1 : Mth[i]);
if(x > del) x -= del;
else break;
}
M = i;
D = x;
ans2: cout << D << ' ' << M << ' ' << Y << '\n';
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(nullptr), cout.tie(nullptr);
cin >> q;
while(q--) solve();
return 0;
}
[CSP-S2020] 动物园
很狗屎的题。
有 \(m\) 个饲料约束条件。如果有条件但是现有的动物没有一个满足的,说明此条件对应的饲料买不到了,因此新加的动物中不能有动物需要这款饲料。
翻译过来就是将 \(a_i\) 全部或运算起来,得到的二进制数。如果条件中 \(q_i\) 的位置为 \(0\),则累计贡献 \(Ans\) 一次。最后满足条件的动物数量便为 \(2^{k-Ans}\)。新增的动物数量为 \(2^{k-Ans}-n\)。
时间复杂度 \(O(n+m)\),最后一个点会爆 long long
,记得开 __int128
。
#include<bits/stdc++.h>
#define int __int128
#define rint register int
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
inline int read() {
rint 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<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
inline void print(int x) {
if(x > 9) {
print(x/10);
putchar(x%10+'0');
} else {
putchar(x+'0');
}
}
const int N = 1e6 + 10;
int n, m, c, k, a[N], Ans;
bitset<64> ans;
bool vis[65];
signed main() {
n = read(), m = read(), c = read(), k = read();
For(i,1,n) {
a[i] = read();
bitset<64> pos(a[i]);
ans |= pos;
}
For(i,1,m) {
int p = read(), q = read();
if(ans[p] == 0 && !vis[p]) Ans++, vis[p] = 1;
}
print(((__int128)1 << (k - Ans)) - n);
return 0;
}