最近训练太不勤快了!决定用 atcoder beginner contest 给25级小登训练的同时,自己也跟上进度。
给自己立下束缚:从 3 月 16 号开始,到下一个大事件发生为止。必须同步补完训练的每场abc。并且对于赛后补的题,把题解写到这个博客!
abc448_e
题解
$\lfloor {n\over m} \rfloor \pmod p \rightleftarrows \lfloor{n \pmod{mp}\over m}\rfloor$, 这样就能先算 $n$。求 $n$ 的难点在于求连续的 $111\dots11$,由于 $9^{-1}\pmod{mp}$ 未必存在,所以要避开求逆。
可以倍增求,记 $R_l = 111\dots11 (len = l)$,那么 $R_{2^k} = R_{2^{k - 1}}\times (10^{2^{k - 1}} + 1)$。预处理出 $R_{2^k}$ 后,$R_l = \sum R_{2^{k_i}}\times 10^{} (l = 2^{k_1} + 2^{k_2} + \dots)$。比如 $R_{11} = 11 ...
system calls
gdb
12> b syscall> backtrace
发现是 usertrap() 调用了 syscall()
翻阅 user/initcode.S 后发现 p->trapframe->a7 是用来存放系统调用号,此时这个值为 0x7,也就是 SYS_exec
打印特权寄存器 $sstatus=0x200000022,说明之前处于用户态
System call tracing
要求你在内核态实现 trace 命令,格式:
1trace [argument] [command]
输出 [command] 从开始到执行结束过程中的 syscall
Xv6 and Unix utilities
完成这一章花了远多于建议的时间,很大程度上是因为我对xv6内核和c语法并不熟悉,比如传实参和字符串函数。
sleep
考虑一下异常情况就行。
pingpong
关于管道:
read/write 的状态号对应 0/1
读写结束后要及时close
find
文件有不同类型,参考 user/ls.c 的框架。
prime
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#include "kernel/types.h"#include "kernel/stat.h"#include "user/user.h"/*给当前数写入管道管道中第一个数必为质数,记录并输出用第一个数筛管道里剩下的所有数,把筛出来的加入下一个管道。*/void sieve(int last_read_p ...
收集一些平时遇到的小巧思题,不限于题目背景。
翻转杯子
题面
圆桌上放4个相同的杯子,初始时开口朝向未知。玩家蒙眼(无法分辨正反)同时翻转任意数量杯子:如果让所有杯子都朝向相同,那么游戏结束;否则圆桌旋转随机角度,然后继续上述过程。问:有无一种策略,能使得能在有限步内结束游戏?
题解
开口方向视为0/1,翻转视为异或,每次操作后的旋转圆桌视为对原01序列循环右移。
首先考虑操作的所有情况:
翻转一个杯子,由对称性,有一种情况 xor 0001
翻转两个杯子,由对称性,一共有两种不同的情况:xor 0101 和 xor 0011
翻转三个杯子等价于翻转一个杯子
翻转四个杯子等价于不翻转
所以一共只有三种有效操作,分别是对原序列异或上: 0001 0101 0011
记序列1为 0001, 序列2为 0011,序列3为 0101。
然后考虑序列的所有情况:
同上,所有不重复的状态有 0001, 0011, 0101 和 0000
多记一个序列0为 0000
那么能得到下面的状态机表(由于xor的交换律,只算一半即可):
操作
原状态
xor 1
xor 2
xor ...

