「赛后总结」CSP-S 2020
题目/题解
T1
出题人一定有很多马。
对询问离线,一年一年的加。
期望得分:90
实际得分:40
在考场上我竟然觉得自己能调出来/xk
二分答案所在的年份,然后 day by day 的增加天数计算具体哪一天。
100pts:
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
ll r;
int q, y, m, d;
int ny[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int sy[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool issy(int x) {
bool flag1 = (x % 400 == 0);
bool flag2 = ((x % 4 == 0) && (x % 100 != 0));
return flag1 || flag2;
}
bool isry(int x) {
if (x < 0 && (0 - x - 1) % 4 == 0) return true;
if (x > 0 && x <= 1582 && x % 4 == 0) return true;
if (x > 1582) return issy(x);
return false;
}
ll check(int y, ll tot = 0) {
int bf = min(0, y) + 4713;
int ry = (bf + 3) / 4;
tot += 1ll * bf * 365 + 1ll * ry;
if (y <= 0) return tot;
int af = y - 1;
if (af >= 1582) {
ry = 1582 / 4;
tot += 1ll * 1582 * 365 + 1ll * ry - 1ll * 10;
if (af == 1582) return tot;
int now = 1582;
while (now < af) {
++now;
if (issy(now)) tot += 1ll * 366;
else tot += 1ll * 365;
if (now == af || now == 1600) break;
}
if (now == af) return tot;
af -= 1600;
ry = af / 4 - af / 100 + af / 400;
tot += 1ll * af * 365 + 1ll * ry;
return tot;
}
else {
ry = af / 4;
tot += 1ll * af * 365 + 1ll * ry;
}
return tot;
}
int main() {
scanf("%d", &q);
while (q--) {
scanf("%lld", &r); y = 0;
int L = -4713, R = 1e9 + 518;
while (L <= R) {
int mid = (L + R) >> 1;
if (check(mid) > r) R = mid - 1;
else y = mid, L = mid + 1;
}
r -= check(y);
m = 1, d = 1;
while (r--) {
if (y == 1582 && m == 10 && d == 4) d = 15;
else ++d;
bool typ = isry(y);
if (typ) {
if (d > sy[m]) {
++m, d = 1;
if (m > 12) {
++y, m = 1;
if (y == 0) y = 1;
}
}
}
else {
if (d > ny[m]) {
++m, d = 1;
if (m > 12) {
++y, m = 1;
if (y == 0) y = 1;
}
}
}
}
if (y < 0) printf("%d %d %d BC\n", d, m, -y);
else printf("%d %d %d\n", d, m, y);
}
return 0;
}
T2
用 map 直接 T 飞,离散化+数组最慢才300+ms,话说为啥要打标记啊/kk
用 \(a_1,a_2,\dots,a_n\) 表示已有的宠物。
那么根据 \(a_1 \& a_2\& \dots \& a_n\) 可以得到购买饲料的序列。
得到了购买饲料的序列就可以知道编号的二进制位上哪些可以为 \(1\)(设有 \(num\) 个),哪些只能为 \(0\),答案就是 \(2 ^{num} - n\)。小心爆 unsigned long long
。
期望得分:100
实际得分:60
100pts:
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <map>
#define M 1000001
unsigned long long x, bt;
int n, m, c, k, cp[69];
unsigned long long qpow(int a, int b) {
unsigned long long ans = 1, base = a;
while (b) {
if (b & 1) ans = ans * base;
base = base * base;
b >>= 1;
}
return ans;
}
int main() {
scanf("%d %d %d %d", &n, &m, &c, &k);
bt = 0;
for (int i = 1; i <= n; ++i) {
scanf("%llu", &x);
bt |= x;
}
for (int i = 1, p, q; i <= m; ++i) {
scanf("%d %d", &p, &q);
++cp[p];
if (bt & (1ull << p)) --cp[p];
}
int pnum = 0;
for (int i = k - 1; i >= 0; --i) {
if (cp[i] == 0) ++pnum;
}
if (pnum == 64) {
if (n != 0) std::cout << qpow(2, 63) - n + qpow(2, 63) << '\n';
else puts("18446744073709551616");
}
else std::cout << qpow(2, pnum) - n << '\n';
return 0;
}
T3
期望得分:10
实际得分:10
T4
期望得分:0
实际得分:0
总结
用了太多时间在 T1 上,T2没有好好检查,T3、T4暴力没有好好写。
题目读的不认真,T1 有一年十月少了十天一开始不知道(浪费了 30min 调代码),T2 考完试之后才知道 q 互不相同。