5.1考试总结
30 + 0 + 30 + 0 = 60
考场
拿到题先把 4 道题看了一遍。T1 + T4 博弈论感觉不可做,T2 和 T3 两道计数题感觉可以写暴力。
T1 看到题,看到 \(p_{p_i}\) 就想到了建图,这也是当时 C1 题目的 trick。所以我们可以建边找出所有的环。但是关于环长的 SG 函数就一直没推出来。后来下发了一个单独环的代码,发现 \(sg_5 = sg_{13} = 1\),但依旧不知道怎么弄。想了约 1.5h 毫无进展遂开 T2。
T2 是个计数,看到 \(2^n\) 的子集枚举和部分分却是 \(n \le 1000\),感觉没有得分欲望,遂开 T3,发现是 mex,题目清晰,于是写了 30 分的暴力,目前已经 2.5h。
T4 看了看是线段树,不过有一定想法:发现题目中有 \(y\in[x,\min(k,x+m)]\) 的限制, 而 \(m\le5\),所以大概率是博弈论 + 倒序dp,不过没写出来遂放弃。
最后 1h 草草写完了 T1 的暴力,一共就 60 分,感觉自己炸了。
赛后
本来第一次测的时候我只有 30 分,T1 爆 0 了,以为自己连暴力都能写错,但 std 又又又又又出锅了,重测后拿到 30。
T1 结果是打表题,但其实 sg 函数的式子我也没推出来,\(sg_i = mex_{j=0}^{i-1} (sg_j \oplus sg_{i-j-1})\)。暴力打表发现数据范围内只有环长为 \(1,2,5,13,21,31,47,73,99,125,151,177,315,409\) 的先手必胜,特判即可。
#include<bits/stdc++.h>
using namespace std;
const int M = 5e5 + 5;
bool vis[M];
int p[M];
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &p[i]);
vis[i] = 0;
}
for (int i = 1; i <= n; i++) {
if (!vis[i]) {
int cyc = 0, j = i;
while (!vis[j]) {
vis[j] = 1;
j = p[j];
cyc++;
}
if (cyc == 1 || cyc == 2 || cyc == 5 || cyc == 13 || cyc == 21 || cyc == 31 || cyc == 47 || cyc == 73 || cyc == 99 || cyc == 125 || cyc == 151 || cyc == 177 || cyc == 315 || cyc == 409) ans ^= 1; //雷霆
}
}
if (ans) printf("Y\n");
else printf("N\n");
}
return 0;
}
T2 + T4疯狂计数,以后练。T4 似乎思考方向正确?
T3很巧妙的题,给一个机房大佬的题解:link

浙公网安备 33010602011771号