$CSP\ 2020$ 模拟考试 题解报告
\(CSP\ 2020\) 模拟考试 题解报告
得分情况
\(T1\ 90\ Pts\)
\(T2\ 60\ Pts\)
\(T3\ 0\ Pts\)
\(T4\ 0\ Pts\)
总分: \(150\ Pts\)
考试过程
这次的考试过程异常简单
\(T2\) 起手 看错题 调了一个小时 过大样例
转 \(T1\) 死磕三个小时 考试结束
题解
\(T1\) 儒略日
拿 命 死 磕 大 模 拟
写了差不多两个半小时 最后两分钟过了大样例
直接导致没有时间去写别的题 真正考试的时候这样玩就相当于作死了
本来是能够切掉的 但是最后一个点
需要开 \(long\ long\) 然后被卡成了 \(90\)
我感觉是不需要的啊

最暴力的写法 其实跑的挺快的
大模拟 没什么好说的 把题读清楚 注意一下细节
/*
Time: 5.22
Worker: Blank_space
Source: P7075 [CSP-S2020] 儒略日
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define int long long
#define printq printQ(day, month, year)
#define printh printH(day, month, year)
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int P[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//平年
int R[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//闰年
int Q, n, day, month, year;
/*------------------------------------变量定义*/
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void printH(int _day, int _month, int _year) {printf("%lld %lld %lld\n", _day, _month, _year);}//打印公元后
void printQ(int _day, int _month, int _year) {printf("%lld %lld %lld BC\n", _day, _month, _year);}//打印公元前
void clq(int *y) {//
for(int i = 1; i <= 12; i++)
{
if(n >= y[i])
{
n -= y[i];
month++;
if(month == 13) year--, month = 1;
}
else break;
}
day += n;
if(day > y[month]) day -= y[month], month++;
if(month == 13) year--, month = 1;
}
void clh(int *y) {
for(int i = 1; i <= 12; i++)
{
if(n >= y[i])
{
n -= y[i];
month++;
if(month == 13) year++, month = 1;
}
else break;
}
day += n;
if(day > y[month]) day -= y[month], month++;
if(month == 13) year++, month = 1;
}
void work() {
n = read(); year = 4713, month = 1, day = 1;
if(n <= 365) clq(R), printq;
else if(n == 366) year--, printq;
else if(n < 1721424)
{
n -= 366; year--;
int a = n / 1461;
n %= 1461;
year -= a * 4;
if(n <= 1095)
{
int b = n / 365;
n %= 365;
year -= b;
clq(P); printq;
}
else
{
n -= 1095;
year -= 3;
clq(R); printq;
}
}
else if(n == 1721424) day = month = year = 1, printh;
else if(n < 2298519)
{
day = month = year = 1; n -= 1721424;
int a = n / 1461;
n %= 1461;
year += a * 4;
if(n <= 1095)
{
int b = n / 365;
n %= 365;
year += b;
clh(P); printh;
}
else
{
n -= 1095;
year += 3;
clh(R); printh;
}
}
else if(n == 2298519) year = 1581, printh;
else
{
year = 1581; n -= 2298519;
if(n <= 365) clh(P), printh;
else
{
n -= 365; year++;//1582 1 1
if(n <= 276) clh(P), printh;
else if(n <= 355)
{
n -= 276; month = 10; day = 4;//1582 10 4
if(n == 1) day = 15, printh;
else
{
n--; day = 15;//1582 10 15
if(n < 17) day += n, printh;
else if(n == 17) month = 11, day = 1, printh;//1582 11 1
else
{
n -= 17; month = 11; day = 1;//1582 11 1
if(n < 30) day += n, printh;
else if(n == 30) month = 12, printh;//1582 12 1
else if(n < 61)
{
n -= 30; month = 12;//1582 12 1
day += n; printh;
}
else if(n == 61) year = 1583, month = 1, day = 1, printh;//1583 1 1
}
}
}
else if(n < 1086)
{
n -= 355; year = 1583; month = 1; day = 1;
if(n <= 365) clh(P), printh;
else if(n <= 731)
{
n -= 365; year++;
clh(R); printh;
}
}
else if(n == 1086) year = 1585, month = 1, day = 1, printh;//1585 1 1
else if(n < 6930)
{
n -= 1086; year = 1585; month = 1; day = 1;
int a = n / 1461;
n %= 1461;
year += a * 4;
if(n <= 1095)
{
int b = n / 365;
n %= 365;
year += b;
clh(P); printh;
}
else
{
n -= 1095;
year += 3;
clh(R); printh;
}
}
else if(n == 6930) year = 1601, month = 1, day = 1, printh;//1601 1 1
else
{
n -= 6930; year = 1601; month = 1; day = 1;
int x = n / 146097;
n %= 146097;
year += x * 400;
if(n < 109572)//300
{
int y = n / 36524;
n %= 36524;
year += y * 100;//卡到最后一百年
if(n < 35064)//96
{
int a = n / 1461;
n %= 1461;
year += a * 4;
if(n <= 1095)
{
int b = n / 365;
n %= 365;
year += b;
clh(P); printh;
}
else
{
n -= 1095;
year += 3;
clh(R); printh;
}
}
else if(n == 35064) year += 96, printh;
else
{
n -= 35064; year += 96;
int b = n / 365;
n %= 365;
year += b;
clh(P); printh;
}
}
else if(n == 109572) year += 300, printh;
else
{
n -= 109572; year += 300;
int a = n / 1461;
n %= 1461;
year += a * 4;
if(n <= 1095)
{
int b = n / 365;
n %= 365;
year += b;
clh(P); printh;
}
else
{
n -= 1095;
year += 3;
clh(R); printh;
}
}
}
}
}
}
/*----------------------------------------函数*/
signed main() {
freopen("julian.in","r",stdin);
freopen("julian.out","w",stdout);
Q = read(); while(Q--) work();
fclose(stdin);
fclose(stdout);
return 0;
}
/*
365 * 3 = 1095
1095 + 366 = 1461
4712 / 4 = 1178
1178 * 1461 = 1721058 -> 1 1 1
1721058 + 366 = 1721424
1582 - 1 = 1581
1581 - 1 = 1580
1580 / 4 = 395
395 * 1461 = 577095
577095 + 1721424 = 2298519 -> 1581
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 = 273
2298519 + 365 = 2298884
2298519 + 365 + 273 = 2299157
2298519 + 365 + 276 = 2299160
2298519 + 365 + 355 = 2299239 -> 1583
2299970 -> 1585
5844
2305814 -> 1601
30 + 31 = 61
365 + 366 = 731
731 + 355 = 1086
1601-1585 = 16
16 / 4 = 4
4 * 1461 = 5844
5844 + 1086 = 6930
100 - 24 = 76
76 * 365 = 27740
24 * 366 = 8784
27740 + 8784 = 36524 -> 一百年
2342338 -> 1701
2378862 -> 1801
2415386 -> 1901
2451910 -> 2000 12 31
2451911 -> 2001 1 1
146097
2598008 2401
2744105 2801
36524 - 1460 = 35064
36524 * 3 = 109572 -> 三百年
109572 + 36535 = 146097 -> 四百年
365 * 4 = 1460
可以
大概 七点半 开始写
历时两个半小时
到 十点五十七 过了大样例
*/
\(T2\) 动物园
直接统计多少位上一定为 \(0\) 统计剩下多少位 记为 \(t\) 答案就是 \(2^t - n\)
结论看出来了
位运算实现的时候出了点问题
输出可以是负的 没有考虑 而且最后一个点是 \(64\) 位 炸掉了 \(ull\) 比较恶心
/*
Time: 5.26
Worker: Blank_space
Source: P7076 [CSP-S2020] 动物园
*/
/*--------------------------------------------*/
#include<cstdio>
#define ull unsigned long long
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
ull n, m, c, k, ans, limit, S;
/*------------------------------------变量定义*/
inline ull read() {
ull 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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
inline void _print(ull x) {if(x > 9) _print(x / 10); putchar(x % 10 ^ 48);}
void print(ull x) {if(x < 0) putchar('-'), _print(-x); else _print(x);}
/*----------------------------------------函数*/
int main() {
n = read(); m = read(); c = read(); k = read();
for(int i = 1; i <= n; i++) S |= read();
for(int i = 1; i <= m; i++) limit |= 1ull << read(), read();
for(int i = 0; i < k; i++) ans += !((limit >> i) & 1) || ((S >> i) & 1);
if(ans == 64 && !n) puts("18446744073709551616");
else print(ans == 64 ? -n : (1ull << ans) - n);
return 0;
}
\(T3\) 函数调用
其实有一种连脑子都不用的暴力 但是并没有留出时间写 裸敲就有 \(40\) 的暴力
十来分钟写完了... 大概长这样
/*
Time: 5.26
Worker: Blank_space
Source: P7077 [CSP-S2020] 函数调用
*/
/*--------------------------------------------*/
#include<cstdio>
#include<vector>
#define int long long
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 998244353;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, m, a[B], Q;
struct node {
int T, p, v;
std::vector <int> q;
} c[B];
/*------------------------------------变量定义*/
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void ty1(int p, int v) {a[p] = (a[p] + v) % mod;}
void ty2(int v) {for(int i = 1; i <= n; i++) a[i] = a[i] * v % mod;}
void ty3(int i) {
for(int j = 0; j < c[i].q.size(); j++)
{
int x = c[i].q[j];
if(c[x].T == 1) ty1(c[x].p, c[x].v);
if(c[x].T == 2) ty2(c[x].v);
if(c[x].T == 3) ty3(x);
}
}
/*----------------------------------------函数*/
signed main() {
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
m = read();
for(int i = 1; i <= m; i++)
{
int opt = read();
if(opt == 1) c[i].T = opt, c[i].p = read(), c[i].v = read();
else if(opt == 2) c[i].T = opt, c[i].v = read();
else if(opt == 3)
{
c[i].T = opt; int x = read();
for(int j = 1; j <= x; j++) c[i].q.push_back(read());
}
}
Q = read();
for(int i = 1; i <= Q; i++)
{
int x = read();
if(c[x].T == 1) ty1(c[x].p, c[x].v);
else if(c[x].T == 2) ty2(c[x].v);
else if(c[x].T == 3) ty3(x);
}
for(int i = 1; i <= n; i++) printf("%lld ", a[i]);
return 0;
}
/*
真的是一点脑子都不用
正解: 拓扑排序
操作一可以直接统计 考虑将所有的操作都转换为操作一
如果没有操作三 维护一个乘法标记 记录已经被乘了多少 倒着扫 统计每一步的贡献 将原序列也看成是操作一
如果没有操作二 对于函数的调用关系建一个 \(DAG\) 输入的函数为主函数 跑拓扑 统计每一个函数的调用次数 最后处理每一个操作一
某一个函数被执行若干次之后序列被乘 \(k\) 相当于这个函数被执行 \(k\) 次
将所有的操作 \(2\) 和 操作 \(3\) 转化为 操作 \(1\)
/*
Time: 5.26
Worker: Blank_space
Source: P7077 [CSP-S2020] 函数调用
*/
/*--------------------------------------------*/
#include<queue>
#include<vector>
#include<cstdio>
#define int long long
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 998244353;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, m, Q, opt[B], a[B], add[B], cnt[B], mul[B], pos[B], in[B], out[B];
std::vector <int> G1[B], G2[B];
/*------------------------------------变量定义*/
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void scan() {
n = read(); mul[0] = 1; cnt[0] = 1;
for(int i = 1; i <= n; i++) a[i] = read();
m = read();
for(int i = 1; i <= m; i++)
{
opt[i] = read();
if(opt[i] == 1) pos[i] = read(), add[i] = read(), mul[i] = 1;
else if(opt[i] == 2) mul[i] = read();
else if(opt[i] == 3)
{
int x = read(); mul[i] = 1;
for(int j = 1; j <= x; j++)
{
int y = read(); in[y]++; out[i]++;
G2[i].push_back(y); G1[y].push_back(i);
}
}
}
Q = read();
for(int i = 1; i <= Q; i++)
{
int x = read(); in[x]++; out[0]++;
G2[0].push_back(x); G1[x].push_back(0);
}
}
void topo1() {
std::queue <int> q;
for(int i = 0; i <= m; i++) if(!out[i]) q.push(i);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = 0; i < G1[u].size(); i++)
{
int v = G1[u][i];
mul[v] = mul[u] * mul[v] % mod;
out[v]--; if(!out[v]) q.push(v);
}
}
}
void topo2() {
std::queue <int> q;
for(int i = 0; i <= m; i++) if(!in[i]) q.push(i);
while(!q.empty())
{
int u = q.front(), tmp = 1; q.pop();
for(int i = G2[u].size(); i; i--)
{
int v = G2[u][i - 1];
cnt[v] = (cnt[v] + cnt[u] * tmp % mod) % mod;
tmp = tmp * mul[v] % mod;
in[v]--; if(!in[v]) q.push(v);
}
}
}
void print() {
for(int i = 1; i <= n; i++) a[i] = a[i] * mul[0] % mod;
for(int i = 1; i <= m; i++) if(opt[i] == 1) a[pos[i]] = (a[pos[i]] + cnt[i] * add[i] % mod) % mod;
for(int i = 1; i <= n; i++) printf("%lld ", a[i]);
}
/*----------------------------------------函数*/
signed main() {
scan(); topo1(); topo2(); print();
return 0;
}
\(ps\): 模数写错调了好久...
\(T4\) 贪吃蛇
来自题解
如果当前最强的蛇吃了最弱的蛇之后不会变成最弱的蛇 一定会吃
有两种情况
- 吃掉后自己仍是最强的蛇 不吃白不吃
- 吃掉后自己不是最强的蛇 但也不是最弱的蛇 当前最强的蛇吃掉当前最弱的蛇一定比它弱 那么就轮到当前最强的蛇头疼了
- 吃掉后自己变成最弱的蛇 考虑下一条最强的蛇 是否会吃
如果一号蛇吃掉最弱蛇后变成最弱的蛇 二号蛇成为最强蛇 如果二号蛇吃掉一号蛇之后还不是最弱的蛇 那么二号蛇一定会吃
如果二号蛇吃掉一号蛇之后变成最弱的蛇 三号蛇成为最强的蛇 如果三号蛇吃掉二号蛇之后还不是最弱的蛇 那么三号蛇一定会吃
如果三号蛇吃掉二号蛇之后变成最弱的蛇 四号蛇成为最强的蛇 如果...
可以发现这是一个递归问题 边界就是某一条蛇吃掉最弱的蛇之后不是最弱的蛇 或者 只剩下两条蛇
最后一条蛇后顾无忧 直接开吃 倒数第二条蛇就怂了 那么倒数第三条蛇就可以肆意妄为 倒数第四条蛇就不敢吃 倒数第五条蛇就...
很明显的奇偶关系
当出现这中情况 第一条蛇如果选择不吃 结束 如果选择吃 第二条蛇一定不吃 同样结束
游戏分为两个阶段
- 所有最强蛇吃后都不是最弱蛇 吃
- 所有最强蛇吃后都变成最弱蛇 直到有一条蛇敢吃
阶段一结束时游戏基本结束 根据奇偶性判断是否可以再吃
正解:用两个双端队列维护
先把初始的有序蛇放进 \(q_1\) 里 此时 \(q_1\) 已满足单调性 头部小 尾部大 我们后面会让 \(q_2\) 也满足这样的单调性
第一阶段:
每次从 \(q_1\) \(q_2\) 的尾部取出最强的蛇 从 \(q_1\) 头部取出最弱的蛇 如果吃了以后是最弱的 那就进入第二阶段 否则直接装入 \(q_2\) 的头部
后面进食的蛇肯定是越来越弱的 而且这个阶段最弱的蛇一定在 \(q_1\) 中
第二阶段:
此时最弱的蛇 没必要丢进队列 单独维护一下 因为连续的一段进食后都是最弱的 直到总蛇数等于 \(2\) 或者进食后不是最弱为止 而最强的依旧从 \(q_2\) 的尾部找
/*
Time: 5.26
Worker: Blank_space
Source: P7078 [CSP-S2020] 贪吃蛇
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<queue>
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int T, n, a[C], ans;
/*------------------------------------变量定义*/
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void scan() {
int m = read();
for(int i = 1; i <= m; i++) a[read()] = read();
}
void work() {
std::deque <std::pair <int, int> > q1, q2; int ans;
for(int i = 1; i <= n; i++) q1.push_back({a[i], i});
while(1)
{
if(q1.size() + q2.size() == 2) {ans = 1; break;}
int x, y = q1.front().first, id; q1.pop_front();
if(q2.empty() || !q1.empty() && q1.back() > q2.back()) x = q1.back().first, id = q1.back().second, q1.pop_back();
else x = q2.back().first, id = q2.back().second, q2.pop_back();
std::pair <int, int> now = std::make_pair(x - y, id);
if(q1.empty() || q1.front() > now)
{
ans = q1.size() + q2.size() + 2; int cnt = 0;
while(1)
{
cnt++;
if(q1.size() + q2.size() + 1 == 2) {if(cnt & 1 ^ 1) ans--; break;}
int x, id;
if(q2.empty() || !q1.empty() && q1.back() > q2.back()) x = q1.back().first, id = q1.back().second, q1.pop_back();
else x = q2.back().first, id = q2.back().second, q2.pop_back();
now = {x - now.first, id};
if((q1.empty() || now < q1.front()) && (q2.empty() || now < q2.front()));
else {if(cnt & 1 ^ 1) ans--; break;}
}
break;
}
else q2.push_front(now);
}
printf("%d\n", ans);
}
/*----------------------------------------函数*/
int main() {
T = read() - 1; n = read();
for(int i = 1; i <= n; i++) a[i] = read();
work(); while(T--) scan(), work();
return 0;
}
然后你发现这个和第一篇题解异常相似 无论解释还是代码
总结
合理安排时间 享受健康生活

浙公网安备 33010602011771号