CSP-S2020
CSP-S2020考试题解报告
pots:195
-
T1:40
-
T2:100
-
T3:35
-
T4:20
blank_space 考场现切儒略历%%%%%%%%%%%%%%%%%%
总结:
拿滴都是些无脑暴力分= = wtcl /kk
T1
[CSP-S2020]儒略日
大模拟,数论,二分答案
solution
10': ……
month[2]++;
int qwq=0,mth;
for(int i=1;i<=12;i++){
qwq+=month[i];
if(qwq>=k){
mth=i;
k-=(qwq-month[i]);
printf("%lld %lld 4713 BC\n",k,mth);
break;
}
}
month[2]--;
40':
\(1582\) 年 10 月 14 日(第 2299160 天)之前,实行的是儒略历,每 4 年一闰,考虑周期,每四年一循环,所以可以让 \(r_i\) 对 \(365 * 4 + 1\) 取余,就可以算出大致的年份,以及剩下的天数,最后落在最后一年的哪一个月和哪一天就好了代码
100'
调到最后有数据一直少一年就很难受 * *
\(1582\) 年 10 月 15 日之后,年份是 400 的倍数,或日期年份是 4 的倍数但不是 100 的倍数时,该年为闰年,这就变成了 400 年一循环,可以以 1600 年为起点写 代码
T2
[CSP-S2020] 动物园
进制,位运算
solution
en……
code
/*
work by:Ariel_
*/
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e6 + 5;
int read(){
int x = 0,f = 1; char c = getchar();
while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
return x*f;
}
int n, m, c, k, wei[N];
unsigned long long x, S, ans = 1;
int main(){
//freopen("zoo.in", "r", stdin);
//freopen("zoo.out", "w", stdout);
n = read(), m = read(), c = read(), k = read();
for(int i = 1; i <= n; i++) cin >> x, S |= x;
for (int i = 0; i < k; i++) wei[i] = 1;
for (int i = 0, p, q; i < m; i++) {
p = read(), q = read();
wei[p] = ((1ull << p) & S) ? 1 : 0;
}
if(!n && !m && k == 64){puts("18446744073709551616");exit(0);}
for(int i = 0; i < k; i++) ans = (wei[i] == 1) ? ans *= 2: ans;
cout<<ans - n<<"\n";
return 0;
}
T3
[CSP-S2020] 函数调用
数论,拓扑排序
solution
思路来自 AK_Dream
只有 1,2 类函数,把所有的操作拿出来
如果对 \(X\) 进行操作 \(+2, *3, +1,*5\)
可以看为 \(15*X + 2*15 + 5 * 1\)
发现对每个元素要加的数有影响的只有后体乘的操作,那么每个位置的加数就可以倒着离线处理出来,最后加到原数组里面就好了
对第三个操作无脑递归一下就能得到 40' 的好成绩 代码
根据上面对操作1,2的处理,继续考虑操作 3
因为题目中已经说了,函数不形成递归,所以把所有第三个操作,按顺序向它调用的函数连边,这样会得到一个 \(DAG\)
对于图上的每个点(代表着一种操作),维护一个 \(mul\) 属性,表示执行一次这个操作会给累计的积乘上多少
对于操作 \(1\) ,它的 \(mul=1\);
对于操作 \(2\), 它的 \(mul\) 就等于它要乘上的值
对于操作 \(3\),它的 \(mul\) 等于它直接连向的所有点的 \(mul\) 之积
按照拓扑序倒序扫一遍或者直接 \(dfs\) 即可处理出 \(mul\)
操作 3 中既有加法又有乘法的可以用处理 \(1,2\) 操作的方法对 \(3\) 处理一下代码
T4
[CSP-S2020] 贪吃蛇
20'
只有两条蛇
while(T--){
int k = read();
for(int i = 1, x, y; i <= k; i++){
x = read(), y = read();
a[x] = y;
}
if(a[3] >= a[2] + a[1]) cout<<"1\n";
else cout<<"3\n";
}
100'
两个结论(考试的时候只想了第一个/kk)
开始口胡
当前最强的蛇吃掉最弱的蛇之后,没有成为最弱的蛇,它就选择吃
两种情况:
-
如果最强的蛇吃掉最弱的之后还是最强的,它肯定会吃
-
如果最强的蛇(1号蛇)吃掉最弱的蛇(\(a\) 号蛇)之后,不再是最强了;
证明:
新继最强的蛇如果想要吃,它要吃的蛇一定比 \(a\) 号蛇要强,它也就一定比 \(1\) 号蛇先挂,但蛇都很聪明,所以遇到这种情况, 它一定会尽力不死, 所以 \(a\) 号蛇也必定也不会死
如果最强的蛇吃掉最弱的蛇之后成了最弱的蛇
①②③④ 为每一轮的最强蛇(假设每一轮都吃,吃完之后的最强的)
假设 ① 选择吃的话,成了最弱的此时如果 ② 吃了 ① 不是最弱的,那 ① 就挂了(根据上一个结论)
如果 ② 吃了① 也是最弱的,同样也可以类比得出:如果 ③ 吃掉 ② 是不是最弱的,那么 ② 就挂了,但 ③ 吃掉 ② 之后成了最弱的,那么 ③ 的生死就取决于 ④ 了……………………
直到最后递归到某条蛇吃掉一条蛇之后不是最弱的或者只剩下两条蛇或者只剩下两条蛇了
无论递归到这两个的哪一种情况,递归到最后那条蛇肯定会选择吃,倒数第二条蛇就会选择不吃,倒数第三条蛇就会选择吃,倒数第四条蛇就会选择不吃,倒数第五条蛇就会选择吃………一直递归回去
发现
-
发现此时这条蛇到底吃不吃取决于它到最后一条蛇轮数的奇偶
-
此时这条蛇选择吃还是不吃都会两轮就结束(吃的话下一条肯定不会吃)
@ @
实现
用两个双端队列维护(说实话,维护的过程不大明白)
node
/*
双端队列维护
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const int N = 1000005;
int a[N];
int main() {
int _;
scanf("%d", &_);
int n;
for (int cas = 1; cas <= _; cas++) {
if (cas == 1) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
} else {
int k;
scanf("%d", &k);
while (k--) {
int x, y;
scanf("%d%d", &x, &y);
a[x] = y;
}
}
deque<pair<int, int> > q1, q2;
for (int i = 1; i <= n; i++) {
q1.push_back({a[i], i});
}
int ans;
while (1) {
if (q1.size() + q2.size() == 2) {
ans = 1;
break;
}
int x, id, y;
y = q1.front().first, 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();
}
pair<int, int> now = 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 % 2 == 0) 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 % 2 == 0) ans--;
break;
}
}
break;
} else {
q2.push_front(now);
}
}
printf("%d\n", ans);
}
return 0;
}