「CSP-S2020」题解
开个坑,边改边更,不然等我全部改完都不知道猴年马月了...
儒略日
令人心累的模拟,我想如果我当时没做这道题的话结果一定会更好一点吧...
下来之后听学长说了他的实现思路,也看了他的码(56行,算上头文件),感觉确实挺SB的,但现实就是这样,没写出来就是没写出来。也没什么好抱怨的吧,毕竟是自己做的选择,决策的错误根本上还是经验跟能力不足。与其抱怨还不如吸取教训,以及庆幸今年还有一次机会,多了一张复活券,就要把他的作用发挥到最好。
最后还是磕磕绊绊地把自己考场的代码完善了,没有换思路,连重构带调码花了大半个下午加小半个晚上(当然最后查出来是一个写错变量的sb错误的时候自闭了好半天),如果没有标程帮忙检验的话估计时间会更长,可能换学长的思路或者题解的思路的话的确会好写好调一点,毕竟有代码在那,但写完自己的码也算是给当初考场上SB的自己一个交代吧。
思路:
首先将时间按闰年的计算方式分成两种:1. 1582年10月4号及以前 2. 1582年10月15号及以后
-
这种情况很好做,直接初始年份设为-4713,然后按4年1461的循环节跳即可,跳完循环节在一年年跳,此时判断闰年的方式就是看mod4的余数是否为3(负数要先%4再+4再%4)。最后如果年份>=0了就把年份++。月份也是直接跳即可。
-
先把1582年10月份,11月份,12月份这样散的日子特判掉。然后再判一个1583到1599的,一年年直接暴力跳即可,要注意的是此时闰年的判定方式要改一下。再剩下就是1600年及以后的了,此时直接先跳400年的大循环节,跳完400年直接1年年跳就行,还是注意判断闰年,最多跳399次,数据组数1e5够用了。
需要注意的是跳循环节时我的日期都是默认从某年的1月1日开始的,跳一次就是跳到下一个循环开始年份的1月1号,这样在每个特判点一开始减去特判值的时候要多减一个1。
code: 又臭又长,不建议看,下面有学长的代码,但是当个标程算一下答案还是行的。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int flag = 2299160;
#define int long long
int year[4] = { 366, 365, 365, 365 };
int month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
ll n;
ll nian;
ll yue;
ll tian;
void Solve1() {
nian = -4713;
yue = 1;
tian = 1;
nian += 4 * (n / 1461);
n %= 1461;
for (int i = 0; i < 4; ++i) {
if (n < year[i])
break;
nian++;
n -= year[i];
}
int op = 0;
if (((nian % 4) + 4) % 4 == 3)
op = 1;
for (int i = 0; i < 12; ++i) {
int res = month[i];
if (op && i == 1)
res++;
if (n < res)
break;
yue++;
n -= res;
}
if (nian >= 0)
nian++;
tian += n;
printf("%lld %lld %lld", tian, yue, abs(nian));
if (nian < 0)
printf(" BC\n");
else
printf("\n");
}
void Solve2() {
n -= flag;
if (n <= 17) {
nian = 1582;
yue = 10;
tian = 14 + n;
} else if (n <= 47) {
nian = 1582;
yue = 11;
tian = n - 17;
} else if (n <= 78) {
nian = 1582;
yue = 12;
tian = n - 47;
} else if (n <= 443) {
nian = 1583;
yue = 1;
n -= 78;
for (int i = 0; i < 12; ++i) {
int res = month[i];
if (n <= month[i])
break;
yue++;
n -= res;
}
tian = n;
} else if (n <= 6287) {
n -= 444;
nian = 1584;
int res;
if (nian % 400 == 0)
res = 366;
else {
if (nian % 100 == 0)
res = 365;
else if (nian % 4 == 0)
res = 366;
else
res = 365;
}
while (n >= res) {
nian++;
n -= res;
if (nian % 400 == 0)
res = 366;
else {
if (nian % 100 == 0)
res = 365;
else if (nian % 4 == 0)
res = 366;
else
res = 365;
}
}
yue = 1;
int op = 0;
if (nian % 400 == 0)
op = 1;
else {
if (nian % 100 == 0)
op = 0;
else if (nian % 4 == 0)
op = 1;
else
op = 0;
}
for (register int i = 0; i < 12; ++i) {
res = month[i];
if (i == 1 && op)
res++;
if (n < res)
break;
n -= res;
yue++;
}
tian = 1 + n;
} else {
n -= 6288;
nian = 1600;
nian += 400 * (n / 146097);
n %= 146097;
int res = 366;
while (n >= res) {
nian++;
n -= res;
if (nian % 400 == 0)
res = 366;
else {
if (nian % 100 == 0)
res = 365;
else if (nian % 4 == 0)
res = 366;
else
res = 365;
}
}
int op = 0;
if (nian % 400 == 0)
op = 1;
else {
if (nian % 100 == 0)
op = 0;
else if (nian % 4 == 0)
op = 1;
else
op = 0;
}
yue = 1;
for (register int i = 0; i < 12; ++i) {
res = month[i];
if (i == 1 && op)
res++;
if (n < res)
break;
n -= res;
yue++;
}
tian = 1 + n;
}
printf("%lld %lld %lld\n", tian, yue, nian);
}
signed main() {
freopen("julian.in", "r", stdin);
freopen("julian.out", "w", stdout);
int t;
cin >> t;
while (t--) {
scanf("%lld", &n);
if (n <= flag)
Solve1();
else
Solve2();
}
}
更优美的学长考场代码:
#include <bits/stdc++.h>
const int num[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool check(int x) {
if (x < 1582) return x % 4 == 0;
else return x % 400 == 0 || (x % 4 == 0 && x % 100);
}
int daynum(int y, int m) {
if (m == 2) return 28 + check(y);
else return num[m];
}
int main() {
freopen("julian.in", "r", stdin);
freopen("julian.out", "w", stdout);
int q;
std::cin >> q;
while (q--) {
int y, m;
long long n, d;
scanf("%lld", &n);
if (n >= 2299161) {
n -= 2299161, y = 1582, m = 10, d = 15 + n;
while (d > 14609700000) d -= 14609700000, y += 40000000;
while (d > 1460970000 ) d -= 1460970000 , y += 4000000;
while (d > 146097000 ) d -= 146097000 , y += 400000;
while (d > 14609700 ) d -= 14609700 , y += 40000;
while (d > 1460970 ) d -= 1460970 , y += 4000;
while (d > 146097 ) d -= 146097 , y += 400;
if (d > 31) {
d -= 31, ++m;
if (d > 30) {
d -= 30, ++m;
if (d > 31) {
d -= 31, m = 1, ++y;
}
}
}
while (d > 365 + check(y)) d -= 365 + check(y++);
while (m < 12 && d > daynum(y, m)) d -= daynum(y, m++);
}
else {
y = -4712, m = 1, d = 1 + n;
while (d > 1461000) d -= 1461000, y += 4000;
while (d > 146100 ) d -= 146100 , y += 400;
while (d > 365 + check(y)) d -= 365 + check(y++);
while (m < 12 && d > daynum(y, m)) d -= daynum(y, m++);
}
if (y <= 0) --y;
printf("%lld %d %d", d, m, (int)std::abs(y));
if (y <= 0) puts(" BC");
else puts("");
}
}
动物园
SB题,我没写出来,我是SB。
在保证\(q_i\)互不相同的情况下,\(c\)跟\(q_i\)除了影响你读入之外卵用没有。
显然直接考虑每一位就行,如果一个二进制位没被限制或者已经养的动物里这一位上有1,那么cnt+1。
维护养的动物的每一位的1的情况直接求或和即可,因为只要有一个是1就行。跟没被限制的位取并。
答案就是\(2^{cnt}-n\)
\(1ull<<64\)是未定义的,会出错,可以写成\((0ull-n)\)或者\(((1ull << 63) << 1) - n\)
注意这玩意最大连 unsigned long long 都能爆,此时只能用计算器手算然后特判输出。
#include <cstdio>
#include <iostream>
typedef unsigned long long ull;
int n, m, c, K, pos, cnt;
ull st, x;
bool hav[66];
int main() {
//freopen("zoo.in", "r", stdin), freopen("zoo.out", "w", stdout);
std:: cin >> n >> m >> c >> K;
for (int i = 1; i <= n; ++i) scanf("%llu", &x), st |= x;
for (int i = 1; i <= m; ++i) scanf("%d", &pos), hav[pos] = 1, scanf("%d", &pos);
for (ull i = 0; i < K; ++i) cnt += ((st >> i) & 1) || !hav[i];
if (!n && cnt == 64) puts("18446744073709551616");
else if (cnt == 64) std:: cout << 0ull - n ;
else std:: cout << (1ull << cnt) - n ;
return 0;
}
函数调用
看大佬博客吧,我也是看的这篇:比我小但是能把我按在地上踩的大佬
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace PiGeonZ {
int s, w;
char buf[1 << 20], *p1 = buf, *p2 = buf, c;
#define gc() (p1 == p2 ? ((p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin)) == p1 ? EOF : *p1++) : *p1++)
inline int read() {
s = 0, w = 1, c = gc();
while (c < '0' || c > '9') { if (c == '-') w = -1; c = gc(); }
while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = gc();
return s * w;
}
}
using PiGeonZ:: read;
const int maxn = 1e5 + 10;
const int maxm = 1e6 + 10;
const int mod = 998244353;
int n, m, Q, mult;
int a[maxn], q[maxn], f[maxn], add[maxn], deg[maxn], tpy[maxn], pos[maxn], val[maxn], mul[maxn];
bool vis[maxn];
vector<int> e[maxn];
queue<int> que;
void dfs(int u) {
vis[u] = 1;
mul[u] = (tpy[u] == 2 ? val[u] : 1);
for (int i = 0; i < (int) e[u].size(); ++i) {
int v = e[u][i];
if (!vis[v]) dfs(v);
mul[u] = 1ll * mul[u] * mul[v] % mod;
}
}
int main() {
register int i, j, c, x, u, v;
n = read();
for (i = 1; i <= n; ++i) a[i] = read();
m = read();
for (i = 1; i <= m; ++i) {
tpy[i] = read();
if (tpy[i] == 1) pos[i] = read(), val[i] = read();
else if (tpy[i] == 2) val[i] = read();
else {
c = read();
for (j = 1; j <= c; ++j) x = read(), e[i].push_back(x), deg[x]++;
}
}
for (i = 1; i <= m; ++i) if (!vis[i] && !deg[i]) dfs(i);
Q = read(); for (i = 1; i <= Q; ++i) q[i] = read();
mult = 1;
for (i = Q; i > 0; --i) {
if (tpy[q[i]] == 1) f[q[i]] = (f[q[i]] + mult) % mod;
else if (tpy[q[i]] == 2) mult = 1ll * mult * val[q[i]] % mod;
else f[q[i]] = (f[q[i]] + mult) % mod, mult = 1ll * mult * mul[q[i]] % mod;
}
for (i = 1; i <= m; ++i) if (!deg[i]) que.push(i);
while (!que.empty()) {
u = que.front(); que.pop();
if (tpy[u] == 1) add[pos[u]] = (add[pos[u]] + 1ll * val[u] * f[u] % mod) % mod;
int res = f[u];
for (j = (int) e[u].size() - 1; j >= 0; --j) {
v = e[u][j];
if (--deg[v] == 0) que.push(v);
f[v] = (f[v] + res) % mod, res = 1ll * res * mul[v] % mod;
}
}
for (i = 1; i <= n; ++i) printf("%lld ", (1ll * a[i] * mult + add[i]) % mod);
return 0;
}