<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>LabLog</title><description>未来道具研究所</description><link>https://c0d4.ink/</link><language>zh_CN</language><item><title>NTE Movie Replacement</title><link>https://c0d4.ink/posts/tutorial-for-nte-movie-replacement/</link><guid isPermaLink="true">https://c0d4.ink/posts/tutorial-for-nte-movie-replacement/</guid><description>仅供交流学习使用</description><pubDate>Sat, 02 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;声明：&lt;/p&gt;
&lt;p&gt;方法是基于3dmigoto和dx11渲染的图层替换，所以并非直接替换视频文件，是具有相同效果的伪视频。&lt;/p&gt;
&lt;p&gt;&lt;s&gt;别问为什么不直接替换，问就是即使解包了也还有一层视频加密搞不定。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;由于同样的原因，方法无法实现音频替换，视频里的是后期配音。&lt;/p&gt;
&lt;p&gt;这些问题留给大佬们解决。orz&lt;/p&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://pan.baidu.com/s/1PJlNiFKMbassuJYZ2_lfNA&quot;&gt;云盘链接&lt;/a&gt;下载工具包到本地，密码 &lt;code&gt;2333&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解压后打开文件夹，进入 &lt;code&gt;3dmigoto&lt;/code&gt; ，用记事本编辑 &lt;code&gt;d3dx.ini&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;按 &lt;code&gt;Ctrl+F&lt;/code&gt; 输入 &lt;code&gt;make any changes&lt;/code&gt; ，找到这一行下面的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;target = D:\NTE\Neverness To Everness\Client\WindowsNoEditor\HT\Binaries\Win64\HTGame.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打开异环游戏目录，依次进入&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Neverness To Everness → Client → WindowsNoEditor → HT → Binaries → Win64&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;找到 &lt;code&gt;HTGame.exe&lt;/code&gt;，选中后右键选择复制文件地址。&lt;/p&gt;
&lt;p&gt;用复制的地址替换掉刚才 &lt;code&gt;d3dx.ini&lt;/code&gt; 里找到的路径，&lt;strong&gt;删去引号&lt;/strong&gt;，&lt;strong&gt;保留等号左右的空格&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;确保格式为&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;target = 你复制的地址&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;保存 &lt;code&gt;d3dx.ini&lt;/code&gt; 并退出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;退回到 &lt;code&gt;replace_movie&lt;/code&gt; 目录，将你想替换的视频（MP4格式）复制进该目录，重命名为 &lt;code&gt;input.mp4&lt;/code&gt; 。（请展开文件扩展名，否则会变成 &lt;code&gt;input.mp4.mp4&lt;/code&gt; ）&lt;/p&gt;
&lt;p&gt;双击 &lt;code&gt;launcher.bat&lt;/code&gt; ，命令行会自动检测环境。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果提示缺少python环境，请自行前往python官网下载并配置环境。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;命令行提示“生成完成！”后，退出命令行，将新生成的 &lt;code&gt;Cinema&lt;/code&gt; 文件夹放到 &lt;code&gt;3dmigoto\Mods&lt;/code&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;退回到 &lt;code&gt;3dmigoto&lt;/code&gt; ， 双击运行该目录下的 &lt;code&gt;3DMigoto Loader.exe&lt;/code&gt; ，授权管理员权限。&lt;/p&gt;
&lt;p&gt;运行异环启动器，点击左上角的齿轮图标，勾选游戏启动设置“游戏使用DX11”。&lt;/p&gt;
&lt;p&gt;点击开始游戏。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注： &lt;code&gt;3DMigoto Loader.exe&lt;/code&gt; 在开始游戏若干秒后会自动退出，这是正常的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;控制角色进入电影院放映厅，按 F10 完成替换。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果想更改载入视频的帧率和画质，可以修改 &lt;code&gt;make_frame.py&lt;/code&gt; 的参数区域（11~34行）&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：&lt;/p&gt;
&lt;p&gt;因为该方法基于注入图形渲染，所以比较吃显存。&lt;/p&gt;
&lt;p&gt;总占用 ≈ 单张 DDS 大小 × 总帧数&lt;/p&gt;
&lt;p&gt;建议量力而行，显存低的话不要加载太多帧数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;完结撒花~&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1RYoGBqE8C/?share_source=copy_web&amp;amp;vd_source=7ba930e23e8552dc60459f63e42ad291&quot;&gt;3DMigoto-for-NTE by leDoctor&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1d8oyBfE6E/?share_source=copy_web&amp;amp;vd_source=7ba930e23e8552dc60459f63e42ad291&quot;&gt;贴图替换思路 by 余晖森林&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;p&gt;如有疑问请B站私信或在评论区留言&lt;/p&gt;
</content:encoded></item><item><title>Hgame Final 2026</title><link>https://c0d4.ink/posts/hgame2026final/</link><guid isPermaLink="true">https://c0d4.ink/posts/hgame2026final/</guid><description>两道re</description><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;https://hgame.vidar.club/games/10&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;juncrypt&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;汇编，好看爱看&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;main有一段诡异的逻辑&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  v4 = sub_12B0(s_1, _r_n);
  if ( v4 &amp;lt; 0 )
  {
    puts(&quot;runtime error&quot;);
    return 1;
  }
  Wrong = &quot;Wrong&quot;;
  if ( v4 )
    Wrong = &quot;Correct&quot;;
  puts(Wrong);  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在sub_12B0函数的最后有&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    munmap(addr_1, 0x2DAu);
  }
  return 0xFFFFFFFFLL;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;v4 &amp;lt; 0&lt;/code&gt;恒成立，&lt;code&gt;Wrong = &apos;Correct&apos;&lt;/code&gt;不可能执行&lt;/p&gt;
&lt;p&gt;所以真正的校验没有在pseudocode里体现&lt;/p&gt;
&lt;p&gt;sub_12B0调用sub_1260完成了对shellcode的加载，存入mmap申请的内存&lt;/p&gt;
&lt;p&gt;只要获得shellcode，就能恢复校验逻辑&lt;/p&gt;
&lt;p&gt;因为地址的动态性，只能下断点在转移控制流的位置dump shellcode&lt;/p&gt;
&lt;p&gt;看一下&lt;code&gt;mprotect&lt;/code&gt;附近的汇编&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.text:0000000000001394 push    rax
.text:0000000000001395 mov     rax, rbx
.text:0000000000001398 jmp     short loc_13A2

.text:00000000000013A2 push    rax ; 把 Shellcode 的动态地址压入栈顶
.text:00000000000013A3 retn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;断在loc_13A2即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set disable-randomization on
starti

b *0x5555555553a2

commands
    dump binary memory shellcode.bin $rax $rax+0x2da
    quit
end
continue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;dump下&lt;code&gt;shellcode.bin&lt;/code&gt;，拖进ida恢复函数&lt;/p&gt;
&lt;p&gt;是一个自定义加密逻辑，解密逻辑为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ROL1( ROL1(v, s1) ^ flag_char ^ c, s2 ) == t
=&amp;gt; ROL1(v, s1) ^ flag_char ^ c == ROR1(t, s2)
=&amp;gt; flag_char == ROL1(v, s1) ^ c ^ ROR1(t, s2)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;def ror1(val, shift):
    return ((val &amp;amp; 0xFF) &amp;gt;&amp;gt; shift) | ((val &amp;lt;&amp;lt; (8 - shift)) &amp;amp; 0xFF)

def rol1(val, shift):
    return (((val &amp;amp; 0xFF) &amp;lt;&amp;lt; shift) &amp;amp; 0xFF) | ((val &amp;amp; 0xFF) &amp;gt;&amp;gt; (8 - shift))

def ror4(val, shift):
    return ((val &amp;amp; 0xFFFFFFFF) &amp;gt;&amp;gt; shift) | ((val &amp;lt;&amp;lt; (32 - shift)) &amp;amp; 0xFFFFFFFF)

def rol4(val, shift):
    return (((val &amp;amp; 0xFFFFFFFF) &amp;lt;&amp;lt; shift) &amp;amp; 0xFFFFFFFF) | ((val &amp;amp; 0xFFFFFFFF) &amp;gt;&amp;gt; (32 - shift))

a2 = 27
v = rol4(a2, 3)

targets = [
    7, 0x9A, 0xCC, 75, 0x80, 6, 0x97, 38, 44, 95,
    119, 44, 0x95, 0xE4, 0, 34, 109, 8, 0x97, 91,
    0xE7, 0xDD, 55, 50, 0x8B, 1, 0x8E
]

c_vals = [(0x5A + i * 0x0D) &amp;amp; 0xFF for i in range(27)]

shift1_pattern = [1, 2, 3, 4, 5]
shift2_pattern = [1, 2, 3, 4, 5, 6, 7]

flag = []

for i in range(27):
    s1 = shift1_pattern[i % 5]
    s2 = shift2_pattern[i % 7]
    c = c_vals[i]
    t = targets[i]

    part1 = rol1(v &amp;amp; 0xFF, s1)
    part2 = ror1(t, s2)

    char_code = part1 ^ c ^ part2
    flag.append(chr(char_code))

    v = (ror4(v, 1) + 61) &amp;amp; 0xFFFFFFFF

print(&apos;&apos;.join(flag))
# hgame{junk_asm_and_selfdec}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ez_drv&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;VM + AES + XOR&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ida分析 &lt;code&gt;vuln.sys&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;VM解释器：&lt;code&gt;sub_14000219C&lt;/code&gt;，字节码：&lt;code&gt;qword_140004230&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;AES加密：&lt;code&gt;sub_140001210&lt;/code&gt;，S-box：&lt;code&gt;RijnDael_AES_LONG_140004300&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;AES密文：&lt;code&gt;xmmword_140004210&lt;/code&gt; 、&lt;code&gt;xmmword_140004220&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;逆字节码发现在AES后还有一个XOR处理，XOR key：&lt;code&gt;byte_140004410&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.Cipher import AES
from itertools import cycle

key = b&quot;EzDrvK3y!@#$%^&amp;amp;*&quot;
xor = [0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe]

aes_encrypted = [
    0x32, 0x9a, 0xb6, 0xc, 0x79, 0xf, 0x3b, 0x33,
    0x7, 0x4c, 0x8b, 0x55, 0x96, 0x7c, 0xad, 0x25,
    0x8c, 0x9d, 0xdc, 0x5a, 0xf7, 0xe7, 0x61, 0xf2,
    0xaf, 0x8e, 0x57, 0xfa, 0xa7, 0x4c, 0x25, 0xa
]

ciphertext = bytes([a ^ b for a, b in zip(aes_encrypted, cycle(xor))])
cipher = AES.new(key, AES.MODE_ECB)
flag = cipher.decrypt(ciphertext)

print(flag)
# hgame{vM_AES_XoR_r1ng0_noDbg}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Notes on Cryptohack</title><link>https://c0d4.ink/posts/cryptohack/</link><guid isPermaLink="true">https://c0d4.ink/posts/cryptohack/</guid><description>updating</description><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction to Cryptohack&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;_byte = chr(_integer)
_integer = ord(_byte)
# byte &amp;lt;=&amp;gt; acsii
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;_bytes = bytes.fromhex(_str)
_str = _bytes.hex()
# bytes &amp;lt;=&amp;gt; hex
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;_bytes = _str.encode(&quot;utf-8&quot;)
# str to bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;import base64

_bytes = base64.b64encode(_bytes)
_bytes = base64.b64decode(_bytes)
# base64

custom_table = &quot;&quot;
std_table = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&quot;
_bytes = base64.b64decode(_bytes.translate(str.maketrans(custom_table, std_table)))
# hacked_base64
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.Util.number import *

_integer = bytes_to_long(_bytes)
_bytes = long_to_bytes(_integer)
# integer &amp;lt;=&amp;gt; bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;_bytes = bytes(_integers)
# integers to btyes
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;from pwn import xor

_bytes = xor(A, B, [length])
# xor
# 自动匹配长度(扩展至length)
# 多类型支持(bytes/str/integer)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;https://cryptohack.org/courses/intro/xorkey1/&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据提示，为已知明文攻击&lt;/p&gt;
&lt;p&gt;由$plain \oplus key = cipher$&lt;/p&gt;
&lt;p&gt;得$key = plain \oplus cipher$&lt;/p&gt;
&lt;p&gt;根据泄露出来的&lt;code&gt;b&apos;crypto{&apos;&lt;/code&gt;和密文&lt;/p&gt;
&lt;p&gt;推出key前7位为&lt;code&gt;myXORke&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;猜测完整key为&lt;code&gt;myXORkey&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.Util.number import *
from pwn import xor

hex = 0x0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104
b = long_to_bytes(hex)

key = b&apos;myXORkey&apos;

print(xor(b,key))

# crypto{1f_y0u_Kn0w_En0uGH_y0u_Kn0w_1t_4ll}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Modular Arithmetic&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Extended Euclidean Algorithm&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;证明&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于 $0 \le r_{i+1} &amp;lt; |r_i|$，$r_i$ 序列是一个递减序列，所以本算法可以在有限步内终止。又因为 $r_{i+1} = r_{i-1} - r_i q_i$，$(r_{i-1}, r_i)$ 和 $(r_i, r_{i+1})$ 的最大公约数是一样的，所以最终得到的 $r_k$ 是 $a, b$ 的最大公约数。&lt;/p&gt;
&lt;p&gt;在欧几里得算法正确性的基础上，又对于 $a=r_0$ 和 $b=r_1$ 有等式 $as_i + bt_i = r_i$ 成立（$i = 0$ 或 $1$）。这一关系由下列递推式对所有 $i &amp;gt; 1$ 成立：&lt;/p&gt;
&lt;p&gt;$r_{i+1} = r_{i-1} - r_i q_i = (as_{i-1}+bt_{i-1}) - (as_i+bt_i)q_i = (as_{i-1}-as_iq_i) + (bt_{i-1}-bt_iq_i) = as_{i+1}+bt_{i+1}$&lt;/p&gt;
&lt;p&gt;因此 $s_i$ 和 $t_i$ 满足裴蜀等式($sa+tb=gcd$)，这就证明了扩展欧几里得算法的正确性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def ext_gcd(a,b):
    prev_s,s = 1,0
    prev_t,t = 0,1
    prev_r,r = a,b
    if b == 0:
        return 1,0,a
    while(r):
        q = prev_r//r
        prev_r, r = r, prev_r - q*r
        prev_s, s = s, prev_s - q*s
        prev_t, t = t, prev_t - q*t
    return prev_s,prev_t,prev_r
# 递推

def ext_gcd(a, b):
    if b == 0:
        return a, 1, 0
    else:
        gcd, x, y = ext_gcd(b, a % b)
        return gcd, y, x - (a // b) * y
# 递归
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Fermat&apos;s little theorem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;若p为质数，有&lt;/p&gt;
&lt;p&gt;$a^p \equiv a \pmod{p}$&lt;/p&gt;
&lt;p&gt;若同时p不整除a，有&lt;/p&gt;
&lt;p&gt;$a^{p-1} \equiv 1 \pmod{p}$&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;quadratic residue&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;若在 $\mathbb{F}_p$ 中，有&lt;/p&gt;
&lt;p&gt;$r^2 = a$&lt;/p&gt;
&lt;p&gt;则称 $a$ 为 quadratic residue&lt;/p&gt;
&lt;p&gt;$\pm r$ 则为 $a$ 的两个根&lt;/p&gt;
&lt;p&gt;Legendre&apos;s Symbol:&lt;/p&gt;
&lt;p&gt;判定条件（Euler&apos;s Criterion）：&lt;/p&gt;
&lt;p&gt;$\left(\frac{a}{p}\right) = \begin{cases} 0 &amp;amp; \text{if } a \equiv 0 \pmod{p} \ +1 &amp;amp; \text{if } a \not\equiv 0 \pmod{p}, \text{quadratic residue} \ -1 &amp;amp; \text{quadratic non-residue}\end{cases}$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Legendre&apos;s Symbol&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$\left( \frac{a}{p} \right) \equiv a^{ \frac{p-1}{2} } \pmod{p}$  , $\left( \frac{a}{p} \right) \in \left{1,0,-1\right}$&lt;/p&gt;
&lt;p&gt;该符号具有积性，即&lt;/p&gt;
&lt;p&gt;$\left( \frac{mn}{p} \right) \equiv  \left( \frac{m}{p} \right)·\left( \frac{n}{p} \right) \pmod{p}$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;pow(a, (p-1)//2, p) == 1
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;大于 2 的质数 mod 4 一共只有 1 和 3 两种情况：&lt;/p&gt;
&lt;p&gt;$p \equiv 1 \pmod{4}$ 对应 $\frac{p-1}{2}$ 为偶数，&lt;/p&gt;
&lt;p&gt;$p \equiv 3 \pmod{4}$ 对应 $\frac{p-1}{2}$ 为奇数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;当 $p \equiv 3 \pmod{4}$ 时，可以通过如下公式快速算出root&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root = pow(a, (p+1)//4, p)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;证明&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If $p \equiv 3 \pmod 4$ then $p + 1$ is divisible by 4. If we want to take the square root of $a \pmod p$ then:&lt;/p&gt;
&lt;p&gt;$$
(\pm a^{\frac{p+1}{4}})^2 \equiv a^{\frac{p+1}{2}} \equiv a^{\frac{p-1+2}{2}} \equiv a^{\frac{p-1}{2} + 1} \equiv a^{\frac{p-1}{2}} \cdot a \pmod p
$$&lt;/p&gt;
&lt;p&gt;But since $a$ was chosen to be a quadratic residue (otherwise it has no square roots) it follows that:&lt;/p&gt;
&lt;p&gt;$$
a^{\frac{p-1}{2}} \equiv 1 \pmod p
$$&lt;/p&gt;
&lt;p&gt;And hence the two square roots of $a$ modulo $p$ can in this case be very easily computed as:&lt;/p&gt;
&lt;p&gt;$$
\pm a^{\frac{p+1}{4}}
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;https://cryptohack.org/courses/modular/root1/&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;with open(&quot;output.txt&quot;,&apos;r&apos;) as f:
    exec(f.read())

for a in ints:
    if pow(a, (p-1)//2, p) == 1:
        r = pow(a, (p+1)//4, p)
        flag = max(r,(r*(-1)%p))
print(flag)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 $p \equiv 1 \pmod{4}$ 则复杂一些，通过Tonelli-Shanks解决&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def tonelli_shanks(n, p):
    q, s = p - 1, 0
    while q % 2 == 0:
        q //= 2
        s += 1
    z = 2
    while pow(z, (p - 1) // 2, p) != p - 1:
        z += 1
    c = pow(z, q, p)
    t = pow(n, q, p)
    r = pow(n, (q + 1) // 2, p)
    m = s
    while t != 1:
        temp = t
        i = 0
        for i in range(1, m):
            temp = pow(temp, 2, p)
            if temp == 1:
                break
        b = pow(c, 2**(m - i - 1), p)
        m = i
        c = pow(b, 2, p)
        t = (t * c) % p
        r = (r * b) % p
    return r
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;Chinese Remainder Theorem&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://cryptohack.org/courses/modular/adrien/&quot;&gt;Adrien&apos;s Signs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据 a , p 可以算出 $\left( \frac{a}{p} \right) \equiv 1 \pmod{p}$&lt;/p&gt;
&lt;p&gt;则 a 为模 p 的二次剩余&lt;/p&gt;
&lt;p&gt;根据legendre&apos;s symbol的积性，有&lt;/p&gt;
&lt;p&gt;$\left( \frac{a^e}{p} \right) = \left( \frac{a}{p} \right)^e = (1)^e = 1$&lt;/p&gt;
&lt;p&gt;这意味着对 $\forall e$ , 皆有 $a^e$ 为二次剩余&lt;/p&gt;
&lt;p&gt;也就是说 $e$ 的取值不影响 $a^e$ 的legendre&apos;s symbol&lt;/p&gt;
&lt;p&gt;又根据欧拉准则的第一补充：&lt;/p&gt;
&lt;p&gt;$p \equiv 3 \pmod{4}$ 时，有 $\left( \frac{-1}{p} \right) = -1$&lt;/p&gt;
&lt;p&gt;就可以完成bit与legendre&apos;s symbol的对应&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.Util.number import *

with open(&apos;output.txt&apos;,&apos;r&apos;) as f:
    exec(f.read())

p = 1007621497415251
plain = &apos;&apos;

for c in cipher: # we name the list in output.txt &apos;cipher&apos;
    if pow(c, (p-1)//2 ,p) == 1:
        plain += &apos;1&apos;
    else:
        plain += &apos;0&apos;

plain = long_to_bytes(int(plain,2))
print(plain)

# crypto{p4tterns_1n_re5idu3s}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://cryptohack.org/courses/modular/bionomials/&quot;&gt;Modular Binomials&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;利用二项式展开在模意义下的性质&lt;/p&gt;
&lt;p&gt;$$
(a+b)^n = a^n + a^{n-1}b^1 + \cdots + a^1b^{n-1} + b^n \equiv a^n+b^n \pmod{ab}
$$&lt;/p&gt;
&lt;p&gt;化简原式，再齐次化消掉 p ，获得只含 q 的表达式 X ，利用&lt;/p&gt;
&lt;p&gt;$$
q = gcd(X,N)
$$&lt;/p&gt;
&lt;p&gt;计算出q&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with open(&apos;data.txt&apos;,&apos;r&apos;) as f:
    exec(f.read())

from math import gcd

exp = e1*e2
X = (pow(5,exp,N)*pow(c1,e2,N)-pow(2,exp,N)*pow(c2,e1,N))%N
q = gcd(X,N)
p = N//q
print(&apos;crypto{&apos;+f&apos;{p},{q}&apos;+&apos;}&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Symmetric Cryptography&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;AES&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Key Expansion (expand key to round_keys)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add Round Key (add round_keys into the process through XOR)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confusion (make it non-linear)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sub Bytes (substitution the bytes through S-box)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Diffusion (spread the confusion)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Shift Rows&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mix Columns (matrix multiplication on $GF(2^8)$ field)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;AES_encrypt.png&quot; alt=&quot;AES_encrypt&quot; /&gt;
&lt;img src=&quot;AES_decrypt.png&quot; alt=&quot;AES_decrypt&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://cryptohack.org/courses/symmetric/aes6/&quot;&gt;Bringing It All Together&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;def bytes2matrix(s):
  return [list(s[i:i+4]) for i in range(0, len(s), 4)]

# AddRoundKey
def add_round_key(s,k):
    for i in range(4):
        for j in range(4):
            s[i][j] ^= k[i][j]

# SubBytes

s_box = (
    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
)

inv_s_box = (
    0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
    0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
    0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
    0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
    0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
    0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
    0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
    0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
    0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
    0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
    0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
    0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
    0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
    0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
    0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
    0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,
)

def sub_bytes(s, sbox):
    for i in range(4):
        for j in range(4):
            s[i][j] = sbox[s[i][j]]

# ShiftRows

def shift_rows(s):
    s[0][1], s[1][1], s[2][1], s[3][1] = s[1][1], s[2][1], s[3][1], s[0][1]
    s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
    s[0][3], s[1][3], s[2][3], s[3][3] = s[3][3], s[0][3], s[1][3], s[2][3]


def inv_shift_rows(s):
    s[0][1], s[1][1], s[2][1], s[3][1] = s[3][1], s[0][1], s[1][1], s[2][1]
    s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
    s[0][3], s[1][3], s[2][3], s[3][3] = s[1][3], s[2][3], s[3][3], s[0][3]

# MixColumns

xtime = lambda a: (((a &amp;lt;&amp;lt; 1) ^ 0x1B) &amp;amp; 0xFF) if (a &amp;amp; 0x80) else (a &amp;lt;&amp;lt; 1)

def mix_single_column(a):
    t = a[0] ^ a[1] ^ a[2] ^ a[3]
    u = a[0]
    a[0] ^= t ^ xtime(a[0] ^ a[1])
    a[1] ^= t ^ xtime(a[1] ^ a[2])
    a[2] ^= t ^ xtime(a[2] ^ a[3])
    a[3] ^= t ^ xtime(a[3] ^ u)


def mix_columns(s):
    for i in range(4):
        mix_single_column(s[i])


def inv_mix_columns(s):
    for i in range(4):
        u = xtime(xtime(s[i][0] ^ s[i][2]))
        v = xtime(xtime(s[i][1] ^ s[i][3]))
        s[i][0] ^= u
        s[i][1] ^= v
        s[i][2] ^= u
        s[i][3] ^= v

    mix_columns(s)


N_ROUNDS = 10

key        = b&apos;\xc3,\\\xa6\xb5\x80^\x0c\xdb\x8d\xa5z*\xb6\xfe\\&apos;
ciphertext = b&apos;\xd1O\x14j\xa4+O\xb6\xa1\xc4\x08B)\x8f\x12\xdd&apos;



def expand_key(master_key):
    &quot;&quot;&quot;
    Expands and returns a list of key matrices for the given master_key.
    &quot;&quot;&quot;

    # Round constants https://en.wikipedia.org/wiki/AES_key_schedule#Round_constants
    r_con = (
        0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
        0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
        0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
        0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
    )

    # Initialize round keys with raw key material.
    key_columns = bytes2matrix(master_key)
    iteration_size = len(master_key) // 4

    # Each iteration has exactly as many columns as the key material.
    i = 1
    while len(key_columns) &amp;lt; (N_ROUNDS + 1) * 4:
        # Copy previous word.
        word = list(key_columns[-1])

        # Perform schedule_core once every &quot;row&quot;.
        if len(key_columns) % iteration_size == 0:
            # Circular shift.
            word.append(word.pop(0))
            # Map to S-BOX.
            word = [s_box[b] for b in word]
            # XOR with first byte of R-CON, since the others bytes of R-CON are 0.
            word[0] ^= r_con[i]
            i += 1

        # XOR with equivalent word from previous iteration.
        word = bytes(i^j for i, j in zip(word, key_columns[-iteration_size]))
        key_columns.append(word)

    # Group key words in 4x4 byte matrices.
    return [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)]


def decrypt(key, ciphertext):
    round_keys = expand_key(key) # Remember to start from the last round key and work backwards through them when decrypting
    # Convert ciphertext to state matrix
    s = bytes2matrix(ciphertext)
    # Initial add round key step
    add_round_key(s, round_keys[N_ROUNDS])
    # Do rounds
    for i in range(N_ROUNDS - 1, 0, -1):
        inv_shift_rows(s)
        sub_bytes(s,inv_s_box)
        add_round_key(s,round_keys[i])
        inv_mix_columns(s)

    # Run final round (skips the InvMixColumns step)
    inv_shift_rows(s)
    sub_bytes(s,inv_s_box)
    add_round_key(s,round_keys[0])
    # Convert state matrix to plaintext
    plaintext = &apos;&apos;.join(chr(b) for r in s for b in r)
    return plaintext


print(decrypt(key, ciphertext))
# crypto{MYAES128}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;常见魔改点&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;S-box&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MixColumns 系数矩阵&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rcon&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://cryptohack.org/courses/symmetric/ecb_oracle/&quot;&gt;ECB Oracle&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;ECB 逐字节攻击&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;依据ECB独立block加密的性质，通过用任意字符填充&quot;plaintext&quot;把flag挤到后面去，使得某一block的最后一个byte是想要泄露的flag字节&lt;/p&gt;
&lt;p&gt;发送http请求来获得当前padding的标准密文&lt;/p&gt;
&lt;p&gt;再在字符集里枚举字符，补上flag目标字节的位置，获取密文&lt;/p&gt;
&lt;p&gt;若两段密文目标block完全相同，则当前枚举的字符就是flag目标字节&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import requests
import string

URL = &quot;https://aes.cryptohack.org/ecb_oracle/encrypt/&quot;
session = requests.Session()

def encrypt(s, block):
    hex = s.encode().hex()
    url = f&apos;{URL}{hex}/&apos;
    ret = session.get(url).json()[&apos;ciphertext&apos;]
    return ret[block*32:(block+1)*32]

charset = &apos;}@_-?!#&apos; + string.ascii_letters + string.digits
flag = &apos;crypto{&apos;

for i in range(7, 16*4):
    padding = (31 - i % 16) * &apos;A&apos;
    block = i // 16 + 1
    std = encrypt(padding, block)
    for c in charset:
        payload = padding + flag + c
        exp = encrypt(payload, block)
        if std == exp:
            flag += c
            break
    if flag[-1] == &apos;}&apos;:
        break

print(flag)
# crypto{p3n6u1n5_h473_3cb}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Hgame 2026</title><link>https://c0d4.ink/posts/hgame2026/</link><guid isPermaLink="true">https://c0d4.ink/posts/hgame2026/</guid><description>2026/2/2 ~ 2026/2/15</description><pubDate>Fri, 06 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://hgame.vidar.club/training/9&quot;&gt;https://hgame.vidar.club/training/9&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;week1&lt;/h2&gt;
&lt;h3&gt;PVZ&lt;/h3&gt;
&lt;p&gt;DIE&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;1.png&quot; alt=&quot;1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;发现是一个封装在C++壳下的jar包&lt;/p&gt;
&lt;p&gt;7zip打开gpvz.exe，解压&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;2.png&quot; alt=&quot;2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;jadx分析一下gpvz文件夹，发现一个很扎眼的what_is_this.png&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;3.png&quot; alt=&quot;3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;发现是“神秘仪式”的具体内容&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;4.png&quot; alt=&quot;4&quot; /&gt;&lt;/p&gt;
&lt;p&gt;运行游戏，用一点作弊技巧在结束前摆出神秘阵型，获得flag&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;5.png&quot; alt=&quot;5&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;6.png&quot; alt=&quot;6&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;看不懂的华容道&lt;/h3&gt;
&lt;p&gt;IDA分析&lt;/p&gt;
&lt;p&gt;无符号表，一坨sub_xxxxx函数，没有头绪&lt;/p&gt;
&lt;p&gt;先看看字符串&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;7.png&quot; alt=&quot;7&quot; /&gt;&lt;/p&gt;
&lt;p&gt;点进HuarongDao2026_Salt看看&lt;/p&gt;
&lt;p&gt;跟踪到sub_1400266B0，发现是一个VM的depatcher&lt;/p&gt;
&lt;p&gt;VM控制华容道运作&lt;/p&gt;
&lt;p&gt;game.bin就是操作码表&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;8.png&quot; alt=&quot;8&quot; /&gt;&lt;/p&gt;
&lt;p&gt;opcode：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x15&lt;/code&gt;：读用户输入（交互输入“编号+方向”）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x16&lt;/code&gt;：调用 &lt;code&gt;sub_140011212 -&amp;gt; sub_14001EC40&lt;/code&gt;，重建棋盘状态编码&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x18&lt;/code&gt;：对状态做哈希，写入寄存器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x17&lt;/code&gt;：打印两个 64-bit 组成的节点值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0xE0/E1/E2/E3&lt;/code&gt;：跳转与条件判断&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0xFF&lt;/code&gt;：结束&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;棋盘编码&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;9.png&quot; alt=&quot;9&quot; /&gt;&lt;/p&gt;
&lt;p&gt;分析game.bin恢复初始棋盘为&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[ P1 ][ P0 ][ P0 ][ P2 ]
[ P1 ][ P0 ][ P0 ][ P2 ]
[ P5 ][ P5 ][ P4 ][ P3 ]
[ P6 ][ P8 ][ P4 ][ P3 ]
[ P7 ][ --- ][ --- ][ P9 ]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;加密算法为md5，不过不重要，可以通过编写bfs脚本直接跑出符合题目要求的路径，直接运行exe输入，获得最终棋盘hash&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;特别要注意题目追加的条件：操作路径顺序按照棋子编号从小到大 操作顺序wasd&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;from collections import deque

START = (1, 0, 3, 11, 10, 8, 12, 16, 13, 19)
DIRS = [(&apos;w&apos;, -4), (&apos;a&apos;, -1), (&apos;s&apos;, 4), (&apos;d&apos;, 1)]

def piece_cells(anchor, pid):
    if pid == 0:
        return (anchor, anchor + 1, anchor + 4, anchor + 5)
    if 1 &amp;lt;= pid &amp;lt;= 4:
        return (anchor, anchor + 4)
    if pid == 5:
        return (anchor, anchor + 1)
    return (anchor,)

def valid_shape(anchor, pid):
    r, c = divmod(anchor, 4)
    if pid == 0:
        return r &amp;lt;= 3 and c &amp;lt;= 2
    if 1 &amp;lt;= pid &amp;lt;= 4:
        return r &amp;lt;= 3
    if pid == 5:
        return c &amp;lt;= 2
    return 0 &amp;lt;= anchor &amp;lt; 20

def build_occ(state):
    occ = [-1] * 20
    pcs = []
    for pid, a in enumerate(state):
        if not valid_shape(a, pid):
            return None, None
        cells = piece_cells(a, pid)
        for x in cells:
            if not (0 &amp;lt;= x &amp;lt; 20) or occ[x] != -1:
                return None, None
            occ[x] = pid
        pcs.append(cells)
    return occ, pcs

def can_move(cells, occ, ch, d):
    for x in cells:
        if ch == &apos;a&apos; and x % 4 == 0:
            return False
        if ch == &apos;d&apos; and x % 4 == 3:
            return False
        nx = x + d
        if not (0 &amp;lt;= nx &amp;lt; 20):
            return False
        if occ[nx] != -1 and nx not in cells:
            return False
    return True

def bfs():
    q = deque([START])
    prev = {START: (None, None)}
    while q:
        s = q.popleft()
        if s[0] == 13:
            path = []
            cur = s
            while prev[cur][0] is not None:
                p, act = prev[cur]
                path.append(act)
                cur = p
            path.reverse()
            return path
        occ, pcs = build_occ(s)
        if occ is None:
            continue
        for pid in range(10):
            cells = pcs[pid]
            for ch, d in DIRS:
                if can_move(cells, occ, ch, d):
                    ns = list(s)
                    ns[pid] += d
                    ns = tuple(ns)
                    if ns not in prev:
                        prev[ns] = (s, (pid, ch))
                        q.append(ns)
    return None

if __name__ == &quot;__main__&quot;:
    path = bfs()
    print(len(path))
    print(&quot; &quot;.join(f&quot;{pid}{ch}&quot; for pid, ch in path))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;11.png&quot; alt=&quot;11&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hgame{c4a8ae149d34f8552875b87bb317ffa}&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Signal Storm&lt;/h3&gt;
&lt;p&gt;DIE&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;12.png&quot; alt=&quot;12&quot; /&gt;&lt;/p&gt;
&lt;p&gt;IDA分析&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;13.png&quot; alt=&quot;13&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在main中注册了三个信号处理函数，通过BUG(),raise(5)异常调用，控制执行流&lt;/p&gt;
&lt;p&gt;分析信号处理函数，发现这其实是一个&lt;strong&gt;魔改 RC4 算法&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sub_1780&lt;/code&gt; (KSA)&lt;/strong&gt;：利用原始字符串对 S 盒 (&lt;code&gt;byte_4100&lt;/code&gt;) 进行初始化打乱。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sub_1640&lt;/code&gt; (PRGA变形)&lt;/strong&gt;：这是 RC4 的 S 盒交换逻辑，但它引入了 &lt;code&gt;aC0lmBe4ore7heS&lt;/code&gt; 的当前字符参与运算。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sub_1740&lt;/code&gt; (密钥旋转)&lt;/strong&gt;：每生成一个字节的密钥，就将密钥字符串循环左移一位&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sub_16E0&lt;/code&gt; (异或)&lt;/strong&gt;：执行标准的流密码异或操作：&lt;code&gt;s[i] ^= keystream[i]&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;密文：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;14.png&quot; alt=&quot;14&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Exp:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import struct

def solve():

    key_str = b&quot;C0lm_be4ore_7he_st0rm&quot;

    targets = [
        0x8260C1C9C8D936E3, #s[0:8]
        0x1C4BB2D52511D975, #s[8:16]
        0xF11CAF1C716DE64D, #s[16:24]
        0x1A5AF67F261CA506  #s[24:32]
    ]

    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key_str[i % 21]) % 256
        S[i], S[j] = S[j], S[i]
    i_ptr = 0
    j_ptr = 0
    current_rot_str = list(key_str)
    keystream = []

    for _ in range(32):
        i_ptr = (i_ptr + 1) % 256
        v2 = S[i_ptr]
        j_ptr = (j_ptr + v2 + current_rot_str[i_ptr % 21]) % 256
        S[i_ptr], S[j_ptr] = S[j_ptr], S[i_ptr]
        res_idx = (S[i_ptr] + S[j_ptr]) % 256
        keystream.append(S[res_idx])
        first = current_rot_str.pop(0)
        current_rot_str.append(first)
    ks_qwords = [
        struct.unpack(&quot;&amp;lt;Q&quot;, bytes(keystream[i:i+8]))[0] 
        for i in range(0, 32, 8)
    ]
    flag_parts = []
    for i in range(4):
        flag_parts.append(struct.pack(&quot;&amp;lt;Q&quot;, targets[i] ^ ks_qwords[i]))

    flag = b&quot;&quot;.join(flag_parts)
    print(flag.decode(errors=&apos;ignore&apos;))

if __name__ == &quot;__main__&quot;:
    solve()

# hgame{Null_c0lm_wi7hout_0_storm}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Noncesense&lt;/h3&gt;
&lt;p&gt;IDA分析驱动&lt;/p&gt;
&lt;p&gt;DriverEntry -&amp;gt; sub_14000154C&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;16.png&quot; alt=&quot;16&quot; /&gt;&lt;/p&gt;
&lt;p&gt;MajorFunction[0/2] = sub_140001000&lt;/p&gt;
&lt;p&gt;MajorFunction[14] = sub_1400010C0&lt;/p&gt;
&lt;p&gt;驱动核心在sub_1400010C0&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;17.png&quot; alt=&quot;17&quot; /&gt;&lt;/p&gt;
&lt;p&gt;0x222000：发 nonce&lt;/p&gt;
&lt;p&gt;FsContext 在 open 时通过&lt;code&gt;sub_140001668&lt;/code&gt;生成 16 字节随机值&lt;/p&gt;
&lt;p&gt;0x222004：验签 + 加密&lt;/p&gt;
&lt;p&gt;构造 &lt;code&gt;AUTHv1 || nonce || 0 || len || payload&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;调 &lt;code&gt;sub_140001A7C&lt;/code&gt; 计算 HMAC-SHA256，比较前 16 字节签名&lt;br /&gt;
常量 key：&lt;code&gt;VIDAR_HGAME_A0th_HMaC_K1_bu1ld2026&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sub_1400016B0&lt;/code&gt;：AES 单块加密（可见 Sbox、ShiftRows、MixColumns）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sub_140001908&lt;/code&gt;：AES-128 key schedule（Rcon 常量）&lt;/p&gt;
&lt;p&gt;明文先 PKCS#7 padding，再每 16 字节块加密（ECB）&lt;/p&gt;
&lt;p&gt;会话 AES key 派生&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sub_1400019B8&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;v10 = HMAC_SHA256(key=00*32, msg=nonce16)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;v39&lt;/code&gt; 由 &lt;code&gt;byte_140003250&lt;/code&gt; 经 &lt;code&gt;xor/ror&lt;/code&gt; 变换得到 32 字节&lt;/p&gt;
&lt;p&gt;&lt;code&gt;v11 = HMAC_SHA256(key=v10, msg=v39 || 0x01)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;AES key = &lt;code&gt;v11[:16]&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;KDF（两层 HMAC）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AES-ECB&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;具体数据可以从.rdata，.text字段dump&lt;/p&gt;
&lt;p&gt;IDA分析客户端&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;18.png&quot; alt=&quot;18&quot; /&gt;&lt;/p&gt;
&lt;p&gt;main流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;读用户输入&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;CreateFile(&quot;\\\\.\\GATE_Driver&quot;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;DeviceIoControl(..., 0x222000, ...)&lt;/code&gt; 取 nonce&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对输入每字节跑一段小型“指令机”变换（&lt;code&gt;unk_1400043F3&lt;/code&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;构造 &lt;code&gt;AUTHv1&lt;/code&gt; 包 + HMAC（&lt;code&gt;sub_140001A80&lt;/code&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调 &lt;code&gt;0x222004&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;成功后把返回密文写入 &lt;code&gt;Drv_blob.bin&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;完整解密路线&lt;/p&gt;
&lt;p&gt;从 &lt;code&gt;Drv_blob.bin&lt;/code&gt; 出发：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;取前 16 字节为 &lt;code&gt;nonce&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;剩余为 &lt;code&gt;ciphertext&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用驱动 KDF 复现 AES key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AES-ECB 解密 + 去 PKCS#7 padding，得到client变换后的明文&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按索引逐字节做指令机逆变换，恢复原始输入（flag）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Exp&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.Cipher import AES
import hmac
import hashlib
import sys

BYTE_3250_HEX = &quot;BFE743BAE2BFAB5291E64BA4200E2ED39179FBA4C10A2000F9EF029FEE029645&quot;
byte_3250 = bytes.fromhex(BYTE_3250_HEX)

PROG_RAW = bytes([
    0x05,0x02,0x0D,
    0x04,0x02,0xC3,
    0x02,0x00,0x02,
    0x01,0x03,0x01,
    0x05,0x03,0x03,
    0x04,0x03,0x01,
    0x06,0x03,0x07,
    0x07,0x00,0x03,
    0x03,0x00,0x5A,
    0x00,0x00,0x00, 
    0x00,0x00,0x00, 
    0x00,0x00,0x00
])

def ror8(x: int, r: int) -&amp;gt; int:
    r &amp;amp;= 7
    return ((x &amp;gt;&amp;gt; r) | ((x &amp;lt;&amp;lt; (8 - r)) &amp;amp; 0xFF)) &amp;amp; 0xFF

def rol8(x: int, r: int) -&amp;gt; int:
    r &amp;amp;= 7
    return (((x &amp;lt;&amp;lt; r) &amp;amp; 0xFF) | (x &amp;gt;&amp;gt; (8 - r))) &amp;amp; 0xFF

def pkcs7_unpad(x: bytes) -&amp;gt; bytes:
    if not x:
        return x
    pad = x[-1]
    if pad == 0 or pad &amp;gt; 16 or pad &amp;gt; len(x):
        return x
    if x[-pad:] != bytes([pad]) * pad:
        return x
    return x[:-pad]

def build_v39() -&amp;gt; bytes:
    out = bytearray(32)
    for i in range(32):
        rot = (1 - 3 * i) &amp;amp; 7
        out[i] = ror8(byte_3250[i] ^ 0x5C, rot) ^ 0xA7
    return bytes(out)

def derive_aes_key_from_nonce(nonce16: bytes) -&amp;gt; bytes:
    if len(nonce16) != 16:
        raise ValueError(&quot;nonce must be 16 bytes&quot;)

    # v10 = HMAC_SHA256(key=00*32, msg=nonce)
    v10 = hmac.new(b&quot;\x00&quot; * 32, nonce16, hashlib.sha256).digest()

    # v11 = HMAC_SHA256(key=v10, msg=v39||0x01)
    v39 = build_v39()
    v11 = hmac.new(v10, v39 + b&quot;\x01&quot;, hashlib.sha256).digest()

    return v11[:16]

def client_forward_byte(ch: int, idx: int) -&amp;gt; int:
    st = [ch &amp;amp; 0xFF, idx &amp;amp; 0xFF, 0, 0]
    op = 0
    dst = 2
    src = 1

    p = 0
    for _ in range(256):
        if not (0 &amp;lt;= op &amp;lt;= 6):
            break
        if not (0 &amp;lt;= dst &amp;lt;= 3):
            break

        if op == 0:
            if not (0 &amp;lt;= src &amp;lt;= 3): break
            st[dst] = st[src]
        elif op == 1:
            if not (0 &amp;lt;= src &amp;lt;= 3): break
            st[dst] ^= st[src]
        elif op == 2:
            st[dst] ^= (src &amp;amp; 0xFF)
        elif op == 3:
            st[dst] = (st[dst] + (src &amp;amp; 0xFF)) &amp;amp; 0xFF
        elif op == 4:
            st[dst] = (st[dst] * (src &amp;amp; 0xFF)) &amp;amp; 0xFF
        elif op == 5:
            st[dst] &amp;amp;= (src &amp;amp; 0xFF)
        elif op == 6:
            if not (0 &amp;lt;= src &amp;lt;= 3): break
            st[dst] = rol8(st[dst], st[src] &amp;amp; 7)

        if p + 2 &amp;gt;= len(PROG_RAW):
            break
        b0 = PROG_RAW[p]
        b1 = PROG_RAW[p + 1]
        b2 = PROG_RAW[p + 2]
        p += 3

        dst = b1
        src = b2
        op = ((b0 - 1) &amp;amp; 0xFF)

    return st[0] &amp;amp; 0xFF


def build_inverse_table_for_index(idx: int):
    inv = [-1] * 256
    for b in range(256):
        o = client_forward_byte(b, idx)
        if inv[o] == -1:
            inv[o] = b
    return inv

def inverse_client_transform(data: bytes) -&amp;gt; bytes:
    out = bytearray(len(data))
    for i, c in enumerate(data):
        inv = build_inverse_table_for_index(i &amp;amp; 0xFF)
        v = inv[c]
        if v == -1:
            v = c
        out[i] = v
    return bytes(out)

def solve_blob(blob: bytes):
    if len(blob) &amp;lt; 32:
        raise ValueError(&quot;blob too short&quot;)

    nonce = blob[:16]
    ct = blob[16:]

    if len(ct) % 16 != 0:
        raise ValueError(f&quot;ciphertext len {len(ct)} is not multiple of 16&quot;)

    key = derive_aes_key_from_nonce(nonce)

    pt_trans = AES.new(key, AES.MODE_ECB).decrypt(ct)
    pt_trans = pkcs7_unpad(pt_trans)

    pt_raw = inverse_client_transform(pt_trans)
    return nonce, key, pt_trans, pt_raw


def print_best_text(bs: bytes):
    print(&quot;[+] recovered (bytes):&quot;, bs)
    for enc in (&quot;utf-8&quot;, &quot;gbk&quot;, &quot;latin1&quot;):
        try:
            s = bs.decode(enc)
            print(f&quot;[+] recovered ({enc}): {s}&quot;)
            return
        except Exception:
            pass
    print(&quot;[+] recovered (text): &amp;lt;decode failed&amp;gt;&quot;)


def main():
    in_file = &quot;Drv_blob.bin&quot;
    if len(sys.argv) &amp;gt;= 2:
        in_file = sys.argv[1]

    with open(in_file, &quot;rb&quot;) as f:
        blob = f.read()

    nonce, key, pt_trans, pt_raw = solve_blob(blob)

    print(&quot;[+] file      :&quot;, in_file)
    print(&quot;[+] nonce     :&quot;, nonce.hex())
    print(&quot;[+] aes_key   :&quot;, key.hex())
    print(&quot;[+] trans_len :&quot;, len(pt_trans))
    print(&quot;[+] raw_len   :&quot;, len(pt_raw))
    print(&quot;[+] transformed(hex):&quot;, pt_trans.hex())
    print_best_text(pt_raw)

    low = pt_raw.lower()
    if b&quot;flag{&quot; in low or b&quot;hgame{&quot; in low or b&quot;vidar{&quot; in low:
        print(&quot;[+] possible flag detected.&quot;)


if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;19.png&quot; alt=&quot;19&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;week2&lt;/h2&gt;
&lt;h3&gt;Androuge&lt;/h3&gt;
&lt;p&gt;apktool + jadx&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;20.png&quot; alt=&quot;20&quot; /&gt;&lt;/p&gt;
&lt;p&gt;找按键交互&lt;/p&gt;
&lt;p&gt;游戏本体在waw和game&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;21.png&quot; alt=&quot;21&quot; /&gt;&lt;/p&gt;
&lt;p&gt;分别是程序和数据表&lt;/p&gt;
&lt;p&gt;waw是ARM aarch64架构，no stripped&lt;/p&gt;
&lt;p&gt;逆一下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;22.png&quot; alt=&quot;22&quot; /&gt;&lt;/p&gt;
&lt;p&gt;根据函数名，是一个lua语言编写的程序&lt;/p&gt;
&lt;p&gt;找一下game数据表是在哪里载入的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;lua_load → luaD_protectedparser → f_parser → luaU_undump&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;23.png&quot; alt=&quot;23&quot; /&gt;&lt;/p&gt;
&lt;p&gt;可以看到，是在对dump数据进行校验，每字节数据都xor&lt;code&gt;0x9C&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;猜测game数据表不是明文，而是经过异或加密的密文，&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;24.png&quot; alt=&quot;24&quot; /&gt;&lt;/p&gt;
&lt;p&gt;将前四字节除了第一字节还原后，刚好是&lt;code&gt;.Waw&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;25.png&quot; alt=&quot;25&quot; /&gt;&lt;/p&gt;
&lt;p&gt;dump一下还原后的数据表，发现有不少游戏数据以及flag的信息&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;26.png&quot; alt=&quot;26&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;27.png&quot; alt=&quot;27&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;28.png&quot; alt=&quot;28&quot; /&gt;&lt;/p&gt;
&lt;p&gt;通过这些信息，大概能推断出获取flag的机制：&lt;/p&gt;
&lt;p&gt;在游戏中到达target_floor，程序就会计算出flag并显示出来&lt;/p&gt;
&lt;p&gt;我的思路是直接修改明文数据表，然后再加密回去，用patch后的数据表快速通关获得flag&lt;/p&gt;
&lt;p&gt;在game_dec中检索对应游戏数值的字符串，修改数值&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;29.png&quot; alt=&quot;29&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里很容易就能发现数值段有一个&lt;code&gt;03 XX 00 00 00 00 00 00 00 04&lt;/code&gt;的固定结构&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我第一次尝试的时候直接把target_floor改成了1，结果flag是乱码，说明这个数据影响了flag生成，改为patch一些只优化游戏体验的数值&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;30.png&quot; alt=&quot;30&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后加密回去，在终端用qemu-aarch64跑&lt;code&gt;./waw game_patch&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;花一点时间通关&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;31.png&quot; alt=&quot;31&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;32.png&quot; alt=&quot;32&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Ouroboros&lt;/h3&gt;
&lt;p&gt;运行 jar&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;33.png&quot; alt=&quot;33&quot; /&gt;&lt;/p&gt;
&lt;p&gt;静态分析&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TradeService&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.seal.ouroborosapp.domain;

import com.seal.ouroborosapi.RiskEngine;
import org.springframework.stereotype.Service;

@Service
/* loaded from: ouroboros-app-0.0.1-SNAPSHOT.jar:BOOT-INF/classes/com/seal/ouroborosapp/domain/TradeService.class */
public class TradeService {
    private RiskEngine riskEngine = new RiskPolicy();

    public String executeTrade(String token, double amount) {
        return this.riskEngine.check(token, amount);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;RiskPolicy&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.seal.ouroborosapp.domain;

import com.seal.ouroborosapi.RiskEngine;

/* loaded from: ouroboros-app-0.0.1-SNAPSHOT.jar:BOOT-INF/classes/com/seal/ouroborosapp/domain/RiskPolicy.class */
public class RiskPolicy implements RiskEngine {
    @Override // com.seal.ouroborosapi.RiskEngine
    public String check(String token, double amount) {
        return null;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;return null&lt;/code&gt;，显然不是最终逻辑&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ShadowLoader&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public com.seal.ouroborosapi.RiskEngine initContext() throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.ClassNotFoundException, java.lang.SecurityException, java.io.IOException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException {
        /*
            Method dump skipped, instructions count: 830
            To view this dump change &apos;Code comments level&apos; option to &apos;DEBUG&apos;
        */
        throw new UnsupportedOperationException(&quot;Method not decompiled: com.seal.ouroborosapp.infra.ShadowLoader.initContext():com.seal.ouroborosapi.RiskEngine&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里jadx挂了，直接解包用cfr反编译&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int k = IntegrityVerifier.getDeriveKey();
byte[] d = read(&quot;/application-data.db&quot;); //R_NAME

long s = k &amp;amp; 0xffffffffL;
for i in [0..len-1]:
    s = (s * 1103515245 + 12345) &amp;amp; 0xffffffff
    x = (s &amp;gt;&amp;gt;&amp;gt; 16) &amp;amp; 0xff
    d[i] ^= x

payload = d[128:]
JarInputStream(payload) -&amp;gt; load classes
target class endsWith(&quot;RealRiskEngine&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而核心代码如上&lt;/p&gt;
&lt;p&gt;隐藏了两个关键类：&lt;code&gt;RealRiskEngine&lt;/code&gt;,&lt;code&gt;OuroborosVM&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;所以“衔尾蛇”的含义就是&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;壳中壳 + 动态还原 + 自定义 VM&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;RealRiskEngine&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class RealRiskEngine
implements RiskEngine {
    private static final byte[] LEGACY_STORE = new byte[]{-9, -17, -49, 7, 49, -50, -2, 54, 21, -65, -60, 107, 30, -42, 124, -83, 95, -100, -119, 108, 76, 62, -60, 14, -100, -19, -34, 63, -8, 6, -119, 1, -103, 17, 42, 82, -103, 23, 90, 73, -65, -85, 107, -22, 116, 115, 11, -41};
    private static final String LEGACY_KEY = &quot;Ouroboros_Legacy&quot;;
    private static final String LEGACY_IV = &quot;1234567812345678&quot;;

    public String check(String token, double amount) {
        if (this.checkLegacy(token)) {
            return &quot;Legacy Access: Validated (But version expired).&quot;;
        }
        boolean isCorrect = OuroborosVM.execute(token, amount);
        if (isCorrect) {
            return &quot;ACCESS GRANTED: Core Logic Validated.&quot;;
        }
        return null;
    }

    private boolean checkLegacy(String inputToken) {
        try {
            if (inputToken == null || inputToken.length() &amp;lt; 10) {
                return false;
            }
            IvParameterSpec iv = new IvParameterSpec(LEGACY_IV.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec skeySpec = new SecretKeySpec(LEGACY_KEY.getBytes(StandardCharsets.UTF_8), &quot;AES&quot;);
            Cipher cipher = Cipher.getInstance(&quot;AES/CBC/PKCS5PADDING&quot;);
            cipher.init(2, (Key)skeySpec, iv);
            byte[] original = cipher.doFinal(LEGACY_STORE);
            String decoyFlag = new String(original, StandardCharsets.UTF_8);
            return inputToken.equals(decoyFlag);
        }
        catch (Exception ex) {
            return false;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;尝试AES-CBC解密，解密成功给出fake_flag&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;flag{N0p3_Th1s_1s_A_D3c0y_G0_B4ck}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;失败则走OuroborosVM&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OuroborosVM&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;自定义VM，代码附带超长opcode和handlers，就不贴了&lt;/p&gt;
&lt;p&gt;token(flag)存进&lt;code&gt;memory&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;用&lt;code&gt;derive_key&lt;/code&gt;dec&lt;code&gt;FIRMWARE&lt;/code&gt;获得VM指令流校验token&lt;/p&gt;
&lt;p&gt;已知opcode&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x10&lt;/code&gt;：push immediate (16-bit)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x20&lt;/code&gt;：push token.length&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x30&lt;/code&gt;：load memory[addr]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x35&lt;/code&gt;：xor&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0x4A&lt;/code&gt;：条件跳&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;0xFF&lt;/code&gt;：结束并判断栈顶是否为 1&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;构造z3约束求解器&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;34.png&quot; alt=&quot;34&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Marionette&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;main&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;35.png&quot; alt=&quot;35&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;v6 += 2LL;
v25.m128i_i8[v5++] = v10 | (16 * v9);
...
while ( v5 &amp;lt;= 0xF );
if ( v5 != 16 )
  return 1;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入32个十六进制字符，每两个转成一字节存储，总共16B&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;36.png&quot; alt=&quot;36&quot; /&gt;&lt;/p&gt;
&lt;p&gt;最后memcmp密文&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;37.png&quot; alt=&quot;37&quot; /&gt;&lt;/p&gt;
&lt;p&gt;分析可知是 &lt;code&gt;fork + ptrace&lt;/code&gt; 的木偶&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;38.png&quot; alt=&quot;38&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sub_401D4E&lt;/code&gt;被int3打断，不可读&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;39.png&quot; alt=&quot;39&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xmm1&lt;/code&gt;的值为硬编码&lt;code&gt;xmmword_405020&lt;/code&gt;，用作&lt;code&gt;aeskeygenassist&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;40.png&quot; alt=&quot;40&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;trace_parent&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以dump出off_405070，qword_406338，qword_4075F8，喂给ai纯静态还原状态机，但可操性更强的是动调&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因为子进程会被父进程ptrace控制，所以需要detach child，单独调父进程&lt;/p&gt;
&lt;p&gt;在gdb里直接实现记录idx，打印对应的汇编语块，最后输出idx状态序列&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set pagination off
set confirm off
set disassemble-next-line off

set follow-fork-mode parent
set detach-on-fork on

handle SIGALRM nostop noprint pass
handle SIGPIPE nostop noprint pass

set logging file gdb_trace.log
set logging overwrite on
set logging enabled on

define pidxblk
    set $idx = (unsigned int)$edx
    set $tbl = (unsigned long long)0x405070
    set $tpl = *(unsigned long long*)($tbl + $idx*8)
    printf &quot;[IDX] %u tpl=%#lx\n&quot;, $idx, $tpl
    x/6i $tpl
end

catch fork
commands
    silent
    continue
end

b *0x4015A6
commands
    silent
    pidxblk
    continue
end

run

set logging enabled off
shell awk &apos;/^\[IDX\] /{print $2}&apos; gdb_trace.log &amp;gt; idx_seq.txt

run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;41.png&quot; alt=&quot;41&quot; /&gt;&lt;/p&gt;
&lt;p&gt;分析汇编，发现这600个block含有AES makekey/AES rounds/XOR/垃圾块，核心运算不是很多，按照状态序列求逆即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import re

target = bytes.fromhex(&quot;8cadb48febfd6fae8660ad44c3c75a31&quot;)
key0   = bytes.fromhex(&quot;5a097c137b8d4f2132be3b19af449c01&quot;)

S = [
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
]
IS = [0]*256
for i,v in enumerate(S): IS[v]=i

def xtime(x):
    x &amp;lt;&amp;lt;= 1
    if x &amp;amp; 0x100: x ^= 0x11B
    return x &amp;amp; 0xff

def mul(a,b):
    r = 0
    while b:
        if b &amp;amp; 1: r ^= a
        a = xtime(a)
        b &amp;gt;&amp;gt;= 1
    return r

def rotw(w): return w[1:]+w[:1]
def subw(w): return bytes(S[x] for x in w)
def xorb(a,b): return bytes(x^y for x,y in zip(a,b))

def expand_key(k, rounds):
    ws = [k[i:i+4] for i in range(0,16,4)]
    rcon = 1
    while len(ws) &amp;lt; 4*(rounds+1):
        t = ws[-1]
        if len(ws) % 4 == 0:
            t = xorb(subw(rotw(t)), bytes([rcon,0,0,0]))
            rcon = xtime(rcon)
        ws.append(xorb(ws[-4], t))
    return [b&apos;&apos;.join(ws[i*4:(i+1)*4]) for i in range(rounds+1)]

def b2s(b): return [[b[c*4+r] for c in range(4)] for r in range(4)]
def s2b(s): return bytes(s[r][c] for c in range(4) for r in range(4))

def addk(s, rk):
    k = b2s(rk)
    for r in range(4):
        for c in range(4):
            s[r][c] ^= k[r][c]

def inv_sub(s):
    for r in range(4):
        for c in range(4):
            s[r][c] = IS[s[r][c]]

def inv_shift(s):
    for r in range(1,4):
        s[r] = s[r][-r:] + s[r][:-r]

def inv_mix(s):
    for c in range(4):
        a = [s[r][c] for r in range(4)]
        s[0][c] = mul(a[0],14)^mul(a[1],11)^mul(a[2],13)^mul(a[3],9)
        s[1][c] = mul(a[0],9)^mul(a[1],14)^mul(a[2],11)^mul(a[3],13)
        s[2][c] = mul(a[0],13)^mul(a[1],9)^mul(a[2],14)^mul(a[3],11)
        s[3][c] = mul(a[0],11)^mul(a[1],13)^mul(a[2],9)^mul(a[3],14)

def dec_custom(ct, key, rounds):
    rks = expand_key(key, rounds)
    s = b2s(ct)
    addk(s, rks[rounds]); inv_shift(s); inv_sub(s)
    for r in range(rounds-1,0,-1):
        addk(s, rks[r]); inv_mix(s); inv_shift(s); inv_sub(s)
    addk(s, rks[0])
    return s2b(s)

idx = [int(x) for x in re.findall(r&apos;\d+&apos;, open(&apos;idx_seq.txt&apos;).read())]
txt = open(&apos;gdb_trace.log&apos;).read()

sec = {int(i):b for i,b in re.findall(r&apos;(?ms)^\[IDX\]\s+(\d+)\s*\n(.*?)(?=^\[IDX\]\s+\d+\s*\n|\Z)&apos;, txt)}
body = &apos;&apos;.join(sec.get(i,&apos;&apos;) for i in idx) if sec else txt

rounds = body.count(&apos;aesenc &apos;) + body.count(&apos;aesenclast &apos;) or 12
mid = bytearray(dec_custom(target, key0, rounds))

if &apos;xor&apos; in body and any(x in body for x in (&apos;%al&apos;,&apos;%cl&apos;,&apos;%dl&apos;)):
    for i in range(1,16):
        mid[i] ^= mid[i-1]

print(mid.hex())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;42.png&quot; alt=&quot;42&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>DontDebugMe</title><link>https://c0d4.ink/posts/dontdebugme/</link><guid isPermaLink="true">https://c0d4.ink/posts/dontdebugme/</guid><description>第八届ZJ CTF预赛RE1</description><pubDate>Sat, 08 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;点开pseudocode,&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;DontDebugMe-1.png&quot; alt=&quot;DontDebugMe-1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;发现是对buf2进行加密，&lt;/p&gt;
&lt;p&gt;显然v5就是加密的key&lt;/p&gt;
&lt;p&gt;而sub_401000这个函数就是为key赋值&lt;/p&gt;
&lt;p&gt;那么只要复现sub_401000函数，得出key即可&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里有两个没见过的函数，&lt;/p&gt;
&lt;p&gt;HIWORD:   取出dword中的高位word&lt;/p&gt;
&lt;p&gt;HIBYTE:  取出dword中的高位byte&lt;/p&gt;
&lt;p&gt;不知道没关系，在asm里有很清晰的解释&lt;/p&gt;
&lt;p&gt;(pseudocode里遇到不懂的先看asm)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;DontDebugMe-2.png&quot; alt=&quot;DontDebugMe-2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;DontDebugMe-3.png&quot; alt=&quot;DontDebugMe-3&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#HIWORD
uint32_t val;
uint16_t hi = val &amp;gt;&amp;gt; 16;

#HIBYTE
uint32_t val;
uint8_t hi = val &amp;gt;&amp;gt; 24;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意Buf2的类型，是word，所以从.data段dump的时候注意一下&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;编写dec&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

uint16_t cipher[20] = {
    0xA9E9, 0xA7F8, 0xA2F9, 0xD620, 0xD69A, 
    0xD9C8, 0xD399, 0x85CB, 0xD29B, 0xD5C7, 
    0x8496, 0xD4C9, 0xD89A, 0xD7CA, 0xD59C, 
    0x85C8, 0xD597, 0x859E, 0xD49C, 0x6DCA
};

uint32_t key = 109440544;

int main() {
    for (int i = 0; i &amp;lt; 20; i++) {
        cipher[i] ^= key;
        cipher[i] -= (key&amp;gt;&amp;gt;16);
    }
    for (int i = 0; i &amp;lt; 20; i++) {
        cout.write(reinterpret_cast&amp;lt;char *&amp;gt;(&amp;amp;cipher[i]),sizeof(cipher[i]));
    }
    return 0;
}

// DASCTF{152c147fe66b51dd450e375ce259e74e}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>整型与端序</title><link>https://c0d4.ink/posts/%E6%95%B4%E5%9E%8B%E4%B8%8E%E7%AB%AF%E5%BA%8F/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E6%95%B4%E5%9E%8B%E4%B8%8E%E7%AB%AF%E5%BA%8F/</guid><description>计算机存储的一些小常识</description><pubDate>Fri, 07 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;整型&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;使用IDA分析pseudocode时，在变量名前往往会有cast，表示将这个变量视作这个类型&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;常见的定长整型有：
&lt;code&gt;BYTE WORD DWORD QWORD&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;与C类型有如下对应关系&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Windows 类型&lt;/th&gt;
&lt;th&gt;标准 C 类型&lt;/th&gt;
&lt;th&gt;基础 C 类型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BYTE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint8_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;char&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WORD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint16_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;short&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DWORD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint32_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;QWORD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint64_t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;long long&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;2个16进制数=8个2进制数=1字节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;DWORD example: 0x12345678(32bit四字节)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;QWORD example: 0x0001000200030004(64bit八字节)&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;地址&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;存放数据的地方，指针变量存放的就是地址&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;32位操作系统 地址位宽=32bit=4byte
64位操作系统 地址位宽=64bit=8byte&lt;/p&gt;
&lt;p&gt;在计算机中，地址是&lt;strong&gt;由小变大，从低到高&lt;/strong&gt;的&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;端序&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;端序(Endian)，计算机中字节的存储方式，又称字节序
分为小端序(Little endian)，大端序(Big endian)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在计算机&lt;s&gt;至少x86-64架构是&lt;/s&gt;本地存储为小端序，即低地址（小端）的字节在前（左），高地址的字节在后（右）
由于整型数字是高位在左，低位在右，所以将整型从地址上提取出来时，会自动转为大端序*（实际上与端序无关，但形式是一致的）*&lt;/p&gt;
&lt;p&gt;e.g.
&lt;code&gt;连续地址的四个byte: 01 02 03 04&lt;/code&gt;
&lt;code&gt;DWORD: 0x04030201&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;大端序是网络传输与特定CPU架构使用的，RE一般不会碰到&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;小技巧：IDA在.data段，可以按U直接展开成按地址小端序，再按ctrl+z撤回&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;互转脚本&lt;/h2&gt;
&lt;p&gt;将十六进制定长整型转为字符串输出&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uint32_t example = 0x44434241;
cout.write(reinterpret_cast&amp;lt;char *&amp;gt;(&amp;amp;example), sizeof(example));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将hex_string(兼容spaced情况)转为字符串输出&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

vector&amp;lt;unsigned char&amp;gt; hexToBytes(const string&amp;amp; hex) {
    vector&amp;lt;unsigned char&amp;gt; bytes;
    string clean;
    for (char c : hex)
        if (!isspace(static_cast&amp;lt;unsigned char&amp;gt;(c))) clean += c;

    for (size_t i = 0; i + 1 &amp;lt; clean.size(); i += 2)
        bytes.push_back(static_cast&amp;lt;unsigned char&amp;gt;(
            stoul(clean.substr(i, 2), nullptr, 16)
        ));
    return bytes;
}

string hex_str=&quot;&quot;;

int main() {
    auto bytes = hexToBytes(hex_str);
    string result(bytes.begin(), bytes.end());
    cout &amp;lt;&amp;lt; result;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>逆向常见加密</title><link>https://c0d4.ink/posts/basic-encryptions-in-re/</link><guid isPermaLink="true">https://c0d4.ink/posts/basic-encryptions-in-re/</guid><description>IDA分析pseudocode时，往往会发现存在加密算法，本篇将介绍几种常见的几种，基础的加密算法要求了解具体原理，因为可以魔改</description><pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;base64&lt;/h2&gt;
&lt;p&gt;将字符从8bit表示转换为6bit表示，映射到给定的&lt;strong&gt;字符表&lt;/strong&gt;（可换），padding为 &lt;strong&gt;&quot;=&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;特征：编码后长度是4的倍数，以及末尾的&quot;=&quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;b64.png&quot; alt=&quot;b64&quot; /&gt;&lt;/p&gt;
&lt;p&gt;前面提到了字符表可换，实际上大部分用到base64的题目都需要换表，以下是b64换表dec&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import base64
import string

#cipher
str1 = &quot;&quot;

#string1为替换表，string2为标准表
string1 = &quot;&quot;
string2 = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&quot;

print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同理，还有base16，base32，事实上base后面的数字就代表了bit表示的数据量，如5bit为$2^{5}=32$ ，6bit为$2^{6}=64$&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;base%E5%AE%B6%E6%97%8F.png&quot; alt=&quot;base家族&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://c0d4.ink/posts/hgame-mini-2025/#easyupx&quot;&gt;EasyUPX&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;MD5&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MD5消息摘要算法&lt;/strong&gt;（MD5 Message-Digest Algorithm），一种被广泛使用的&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%AF%86%E7%A2%BC%E9%9B%9C%E6%B9%8A%E5%87%BD%E6%95%B8&quot;&gt;密码散列函数&lt;/a&gt;，可以产生出一个128位16字节的散列值（hash value），用于确保信息传输完整一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;16bit/32bit Encryption&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import hashlib

def md5_encrypt(text: str, length: int = 32) -&amp;gt; str:
    md5_value = hashlib.md5(text.encode()).hexdigest()  # 32位小写
    if length == 16:  # 取中间16位，也可能是lowercase/uppercase，自行改索引即可
        return md5_value[8:24]
    return md5_value

#cipher
s = &quot;&quot;
print(&quot;MD5(32位):&quot;, md5_encrypt(s, 32))
print(&quot;MD5(16位):&quot;, md5_encrypt(s, 16))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MD5 是&lt;strong&gt;不可逆加密（哈希）算法&lt;/strong&gt;，不存在通用的数学解密方式。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://c0d4.ink/posts/hgame-mini-2025/#z333333&quot;&gt;Z333333&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;TEA&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Tiny Encryption Algorithm， 微型加密算法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Basic-TEA&lt;/h3&gt;
&lt;p&gt;标准TEA，&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0;
    uint32_t delta=0x9e3779b9;
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
    for (uint32_t i = 0; i &amp;lt; 32; i++) {
        sum += delta;
        v0 += ((v1&amp;lt;&amp;lt;4) + k0) ^ (v1 + sum) ^ ((v1&amp;gt;&amp;gt;5) + k1);
        v1 += ((v0&amp;lt;&amp;lt;4) + k2) ^ (v0 + sum) ^ ((v0&amp;gt;&amp;gt;5) + k3);
    }
    v[0]=v0; v[1]=v1;
}

void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720;
    uint32_t delta=0x9e3779b9;
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
    for (uint32_t i = 0; i &amp;lt; 32; i++) {
        v1 -= ((v0&amp;lt;&amp;lt;4) + k2) ^ (v0 + sum) ^ ((v0&amp;gt;&amp;gt;5) + k3);
        v0 -= ((v1&amp;lt;&amp;lt;4) + k0) ^ (v1 + sum) ^ ((v1&amp;gt;&amp;gt;5) + k1);
        sum -= delta;
    }
    v[0]=v0; v[1]=v1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特征：&lt;strong&gt;魔数&lt;/strong&gt;(image number)，即delta，一般为&lt;strong&gt;0x9E3779B9 (-)&lt;/strong&gt;, 减法时为 &lt;strong&gt;0x61C88647(+)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;0x9E3779B9 = - 0x61C88647, 黄金分割比&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;tea.png&quot; alt=&quot;tea&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://c0d4.ink/posts/hgame-mini-2025/#simple-tea&quot;&gt;simple tea&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;XTEA&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;xtea is similar to tea&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;密钥变为根据sum值的轮换使用，&lt;code&gt;&amp;amp;3&lt;/code&gt; 保证了k的索引在0~3&lt;/p&gt;
&lt;p&gt;同时v0,v1的轮换，异或，加法也有调整&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
    for (uint32_t i = 0; i &amp;lt; 32; i++) {
        v0 += (((v1&amp;lt;&amp;lt;4) ^ (v1&amp;gt;&amp;gt;5)) + v1) ^ (sum + k[sum &amp;amp; 3]);
        sum += delta;
        v1 += (((v0&amp;lt;&amp;lt;4) ^ (v0&amp;gt;&amp;gt;5)) + v0) ^ (sum + k[(sum&amp;gt;&amp;gt;11) &amp;amp; 3]);
    }
    v[0]=v0; v[1]=v1;
}

void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=0xC6EF3720;
    for (uint32_t i=0; i&amp;lt;32; i++) {
        v1 -= (((v0&amp;lt;&amp;lt;4) ^ (v0&amp;gt;&amp;gt;5)) + v0) ^ (sum + k[(sum&amp;gt;&amp;gt;11) &amp;amp; 3]);
        sum -= delta;
        v0 -= (((v1&amp;lt;&amp;lt;4) ^ (v1&amp;gt;&amp;gt;5)) + v1) ^ (sum + k[sum &amp;amp; 3]);
    }
    v[0]=v0; v[1]=v1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://c0d4.ink/posts/hgame-mini-2025/#easyxtea&quot;&gt;Easyxtea&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;XXTEA&lt;/h3&gt;
&lt;p&gt;xxtea is complicated&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
    for (uint32_t i = 0; i &amp;lt; 32; i++) {
        sum += delta;
        uint32_t e = (sum &amp;gt;&amp;gt; 2) &amp;amp; 3;
        v0 += (((v1 &amp;lt;&amp;lt; 4) ^ (v1 &amp;gt;&amp;gt; 5)) + (v1 ^ sum)) ^ (k[(0 &amp;amp; 3) ^ e] ^ v1);
        v1 += (((v0 &amp;lt;&amp;lt; 4) ^ (v0 &amp;gt;&amp;gt; 5)) + (v0 ^ sum)) ^ (k[(1 &amp;amp; 3) ^ e] ^ v0);
    }
    v[0] = v0; v[1] = v1;
}

void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=0xC6EF3720;
    for (uint32_t i = 0; i &amp;lt; 32; i++) {
        uint32_t e = (sum &amp;gt;&amp;gt; 2) &amp;amp; 3;
        v1 -= (((v0 &amp;lt;&amp;lt; 4) ^ (v0 &amp;gt;&amp;gt; 5)) + (v0 ^ sum)) ^ (k[(1 &amp;amp; 3) ^ e] ^ v0);
        v0 -= (((v1 &amp;lt;&amp;lt; 4) ^ (v1 &amp;gt;&amp;gt; 5)) + (v1 ^ sum)) ^ (k[(0 &amp;amp; 3) ^ e] ^ v1);
        sum -= delta;
    }
    v[0] = v0; v[1] = v1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;xxtea.png&quot; alt=&quot;xxtea&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a&gt;Hardxxtea&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;RC4&lt;/h2&gt;
&lt;p&gt;&lt;a&gt;EasyUPX+&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;AES&lt;/h2&gt;
&lt;p&gt;&lt;a&gt;AES&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hgame mini 2025</title><link>https://c0d4.ink/posts/hgame-mini-2025/</link><guid isPermaLink="true">https://c0d4.ink/posts/hgame-mini-2025/</guid><description>菜菜</description><pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;EasyUPX&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://hgame.vidar.club/games/8/challenges?challenge=121&quot;&gt;https://hgame.vidar.club/games/8/challenges?challenge=121&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据题目名称，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;upx -d main.exe&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;成功解包，拖入IDA, 先看看Strings&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;EasyUPX-1.png&quot; alt=&quot;EasyUPX-1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;显然这是一个b64换表，dump下custom_table和ciphertext解码即可&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Z333333&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://hgame.vidar.club/games/8/challenges?challenge=105&quot;&gt;https://hgame.vidar.club/games/8/challenges?challenge=105&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;先看Strings,&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Z333333-1.png&quot; alt=&quot;Z333333-1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;获知flag格式，且需要使用MD5加密&lt;/p&gt;
&lt;p&gt;然后分析pseudocode&lt;/p&gt;
&lt;p&gt;有一个reverse函数，看一下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Z333333-2.png&quot; alt=&quot;Z333333-2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;发现实现了一串数字中每组偶数项和奇数项交换，这是一个预处理&lt;/p&gt;
&lt;p&gt;然后看到有check1,check2&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;Z333333-3.png&quot; alt=&quot;Z333333-3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;发现这其实是对用户输入argv[1]这串数字的一系列约束，&lt;/p&gt;
&lt;p&gt;v5,v4分别表示是否满足约束，&lt;/p&gt;
&lt;p&gt;在main中最后的判断中，若v5,v4为true，且满足一个额外条件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;argv[1][6] == 50
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的输入即为plain&lt;/p&gt;
&lt;p&gt;接下来编写脚本即可~~（这题暴搜脚本写起来太麻烦了，请gpt出手）~~&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def reverse_pairs(s: str) -&amp;gt; str:
    lst = list(s)
    for i in range(0, len(lst)//2 * 2, 2):
        lst[i], lst[i+1] = lst[i+1], lst[i]
    return &apos;&apos;.join(lst)

def verify(post: str) -&amp;gt; bool:
    a = [ord(c) for c in post]
    if len(a) &amp;lt; 10:
        return False
    array_dword = 0x00000AF0  #小端存储F0 0A 00 00 
    d404024 = 0x98
    d404028 = 0x9F4
    d40402C = 0x33
    d404030 = 0x53
    d404034 = 0x6B
    d404038 = 0x5
    d40403C = 0x145

    # check2: a[2]+a[1]==107 and a[2]-a[1]==5
    if not (a[2] + a[1] == d404034 and a[2] - a[1] == d404038):
        return False
    # check2 last part: (a5 * a8) &amp;gt;&amp;gt; 3 == 0x145  =&amp;gt; a5*a8 == 0x145 &amp;lt;&amp;lt; 3 == 2600
    if (a[5] * a[8]) &amp;gt;&amp;gt; 3 != d40403C:
        return False
    # check1 first: a0 * a2 == array_dword
    if a[0] * a[2] != array_dword:
        return False
    # next: a5 + a4 + a3 == d404024
    if a[5] + a[4] + a[3] != d404024:
        return False
    # next: a3 * a5 + a4 == d404028
    if a[3] * a[5] + a[4] != d404028:
        return False
    # next: a8 + a6 - a7 == d40402C
    if a[8] + a[6] - a[7] != d40402C:
        return False
    # final: ((a9 + a7) ^ a8) == d404030
    if ((a[9] + a[7]) ^ a[8]) != d404030:
        return False
    # argv[1][6] == 50 constraint (注意：check 在 Reverse 之后，所以这是 post-reverse 的索引)
    if a[6] != 50:
        return False
    return True

# 穷举：&apos;0&apos;-&apos;9&apos;
digits = list(range(48, 58))

solutions = []
# 已知由 check2 解出的 a2=56 (&apos;8&apos;), a1=51 (&apos;3&apos;)
fixed = {0: None, 1:51, 2:56}  # a0 未定 yet (由 a0*a2 == 2800 确定)

# 通过 a0 * a2 == 2800 得到 a0 = 2800 / a2 = 50 (&apos;2&apos;)
array_dword = 0x00000AF0
a2 = 56
a0 = array_dword // a2
if array_dword % a2 != 0:
    raise SystemExit(&quot;无法整除，假设数字范围可能不止 0-9。&quot;)
fixed[0] = a0

# 搜索 a3,a4,a5 满足 a5 + a4 + a3 == 152 且 a3*a5 + a4 == 2548
for a3 in digits:
    for a5 in digits:
        a4 = 152 - (a3 + a5)
        if a4 &amp;lt; 48 or a4 &amp;gt; 57:
            continue
        if a3 * a5 + a4 != 2548:
            continue
        # 现在 a3,a4,a5 满足前半约束，继续搜索 a6,a7,a8,a9
        # 由 (a5 * a8) &amp;gt;&amp;gt;3 == 325 =&amp;gt; a5 * a8 == 325 &amp;lt;&amp;lt; 3 == 2600
        if (a5 * 2600) % a5 != 0:  # 只是形式检查（无实际意义），保留逻辑清晰
            pass
        # a8 必须能整除 2600
        if 2600 % a5 != 0:
            continue
        a8 = 2600 // a5
        if a8 &amp;lt; 48 or a8 &amp;gt; 57:
            continue
        # a6,a7,a9 枚举满足：
        # a8 + a6 - a7 == 51  -&amp;gt; a6 - a7 == 51 - a8
        need_diff = 51 - a8
        for a6 in digits:
            a7 = a6 - need_diff
            if a7 &amp;lt; 48 or a7 &amp;gt; 57:
                continue
            # 最后一个： ((a9 + a7) ^ a8) == 83  -&amp;gt; (a9 + a7) == some value where xor with a8 equals 83
            for a9 in digits:
                if ((a9 + a7) ^ a8) == 83:
                    # 组装 candidate
                    a = [fixed[0], fixed[1], fixed[2], a3, a4, a5, a6, a7, a8, a9]
                    post = &apos;&apos;.join(chr(x) for x in a)
                    if verify(post):
                        solutions.append(post)

for post in solutions:
    original = reverse_pairs(post)  # 程序实际接收的 argv[1]
    print(&quot;post-Reverse 用于校验的字符串:&quot;, post)
    print(&quot;程序实际接收的 argv[1]:&quot;, original)

# post-Reverse 用于校验的字符串: 2380442120
# 程序实际接收的 argv[1]: 3208441202    
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ok，这样就只剩最后一步——MD5(32bit)加密，直接调用python库散列函数生成digest&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import hashlib

def md5_encrypt(text: str, length: int = 32) -&amp;gt; str:
    md5_value = hashlib.md5(text.encode()).hexdigest()  # 32位小写
    if length == 16:
        return md5_value[8:24]  # 取中间16位
    return md5_value

s = &quot;3208441202&quot;
print(&quot;MD5(32位):&quot;, md5_encrypt(s, 32))
print(&quot;MD5(16位):&quot;, md5_encrypt(s, 16))

# MD5(32位): 38435ec59c487c117565576c84476a22
# MD5(16位): 9c487c117565576c
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;这道题一开始上传的是没有argv[1][6]==50约束的版本，存在多解&lt;/p&gt;
&lt;p&gt;以至于苯人做了半天没做出来，怀疑人生了&lt;/p&gt;
&lt;p&gt;好在shiori测过之后紧急更换了版本&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;simple tea&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://hgame.vidar.club/games/8/challenges?challenge=171&quot;&gt;https://hgame.vidar.club/games/8/challenges?challenge=171&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;先分析pseudocode，
发现有tea_encrypt函数，知道这里有tea加密
&lt;s&gt;其实也可以用findcrypt插件，但这里没必要&lt;/s&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;do-while这段循环事实上是用来约束用户输入字符串长度的，
依据v8，v9，v10的检验，可以看出plain长度为3*8=24字节，&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;tea_encrypt的三次调用说明程序是将用户24字节输入拆成3段qword分段加密，&lt;/p&gt;
&lt;p&gt;点进加密函数看一下，
&lt;img src=&quot;simple_tea-1.png&quot; alt=&quot;simple_tea-1&quot; /&gt;
可以发现是标准TEA&lt;/p&gt;
&lt;p&gt;那么接下来只需要获取key，编写dec即可&lt;/p&gt;
&lt;p&gt;点开key看看
&lt;img src=&quot;simple_tea-2.png&quot; alt=&quot;simple_tea-2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这似乎不是真正的key
（当然这是基于猜测，也可以去验证一下）&lt;/p&gt;
&lt;p&gt;这时候看看有没有什么隐藏的初始化函数，改变key的硬编码的&lt;/p&gt;
&lt;p&gt;发现在main上方有一个init_key，
点开看看，
&lt;img src=&quot;simple_tea-3.png&quot; alt=&quot;simple_tea-3&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;建议多按按H将decimal全部转成hex，有时候会下意识搞混&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;显然，key的硬编码在加密前被改成了
&lt;code&gt;74 68 69 73 5F 69 73 5F 72 65 61 6C 5F 6B 79 21&lt;/code&gt;
&lt;code&gt;this_is_real_ky!&lt;/code&gt;
&lt;strong&gt;《疑问句改肯定句》&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这样就获得了正确的key，dec如下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

uint32_t cipher[3][2] = {
    {0xE66A6B7B, 0xA3ECA28E},
    {0x6CCF6CF4, 0x99043B89},
    {0x7EFD20CC, 0xD5536FC9}
};

uint32_t key[4] = {
    0x73696874,0x5F73695F,
    0x6C616572,0x21796B5F
};

void decrypt(uint32_t *v, uint32_t *k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for (i = 0; i &amp;lt; 32; i++) {
        v1 -= ((v0 &amp;lt;&amp;lt; 4) + k2) ^ (v0 + sum) ^ ((v0 &amp;gt;&amp;gt; 5) + k3);
        v0 -= ((v1 &amp;lt;&amp;lt; 4) + k0) ^ (v1 + sum) ^ ((v1 &amp;gt;&amp;gt; 5) + k1);
        sum -= delta;
    }
    v[0] = v0;
    v[1] = v1;
}

int main() {
    for (int i = 0; i &amp;lt; 3; i++) {
        decrypt(cipher[i], key);
        cout.write(reinterpret_cast&amp;lt;char *&amp;gt;(&amp;amp;cipher[i][0]), sizeof(cipher[i][0]));
        cout.write(reinterpret_cast&amp;lt;char *&amp;gt;(&amp;amp;cipher[i][1]), sizeof(cipher[i][1]));
    }
    return 0;
}

// VIDAR{h2llo_7ea_world!!}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Easyxtea&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://hgame.vidar.club/games/8/challenges?challenge=99&quot;&gt;https://hgame.vidar.club/games/8/challenges?challenge=99&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;分析pseudocode,
&lt;img src=&quot;Easyxtea-1.png&quot; alt=&quot;Easyxtea-1&quot; /&gt;
非常简洁清晰的流程，
读入用户32字节字符串，存入Buf2，
将xmmword_140003270的数据读入Buf1，
四组tea家族加密，&lt;/p&gt;
&lt;p&gt;点击v12，v13，v14发现这是在栈上连续的32字节空间，
&lt;img src=&quot;Easyxtea-2.png&quot; alt=&quot;Easyxtea-2&quot; /&gt;
也就是plain存到Buf2的时候事实上后24位是注入到v12，v13，v14的
即
&lt;code&gt;Buf2 = [0~7]&lt;/code&gt;
&lt;code&gt;v12 = [8~15]&lt;/code&gt;
&lt;code&gt;v13 = [16~23]&lt;/code&gt;
&lt;code&gt;v14 = [24~31]&lt;/code&gt;
这就弄清了每组加密是在加密哪段plain，&lt;/p&gt;
&lt;p&gt;点进去看一下是什么茶
&lt;img src=&quot;Easyxtea-3.png&quot; alt=&quot;Easyxtea-3&quot; /&gt;
标准的x茶，
数一下魔数的出现次数为16次，do-while循环&lt;strong&gt;两次&lt;/strong&gt;，即16*2=32轮&lt;/p&gt;
&lt;p&gt;接下来就是获取key和cipher，
pseudocode里有xmmword_1400032XX的数据，点开看看
&lt;img src=&quot;Easyxtea-4.png&quot; alt=&quot;Easyxtea-4&quot; /&gt;
获得key和cipher，
cipher为两组128bit，对应四组x茶加密，&lt;/p&gt;
&lt;p&gt;注意这里有一个坑点，在组合加密后plain的时候，是先xmmword_140003290，后xmmword_140003280
也就是倒过来，90地址段的是cipher前16字节，80段是后16字节，&lt;/p&gt;
&lt;p&gt;编写dec&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

uint32_t cipher[4][2] = {
    {0x9F249FB2, 0x917A3218},
    {0x8CA57C30, 0xD07FB03B},
    {0xE9F399AA, 0x7BF711F4},
    {0x6AA17CFB, 0x31CADE93}
};

uint32_t key[4] = {1,2,3,4};

void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=0xC6EF3720;
    for (uint32_t i=0; i&amp;lt;32; i++) {
        v1 -= (((v0&amp;lt;&amp;lt;4) ^ (v0&amp;gt;&amp;gt;5)) + v0) ^ (sum + k[(sum&amp;gt;&amp;gt;11) &amp;amp; 3]);
        sum -= delta;
        v0 -= (((v1&amp;lt;&amp;lt;4) ^ (v1&amp;gt;&amp;gt;5)) + v1) ^ (sum + k[sum &amp;amp; 3]);
    }
    v[0]=v0; v[1]=v1;
}

int main() {
    for (int i = 0; i &amp;lt; 4; i++) {
        decrypt(cipher[i], key);
        cout.write(reinterpret_cast&amp;lt;char *&amp;gt;(&amp;amp;cipher[i][0]), sizeof(cipher[i][0]));
        cout.write(reinterpret_cast&amp;lt;char *&amp;gt;(&amp;amp;cipher[i][1]), sizeof(cipher[i][1]));
    }
    return 0;
}

// VIDAR{xtea_1s_s1m1lar_t0_tea}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>退役记</title><link>https://c0d4.ink/posts/%E9%80%80%E5%BD%B9%E8%AE%B0/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E9%80%80%E5%BD%B9%E8%AE%B0/</guid><description>2020/02/09-2023/11/18</description><pubDate>Thu, 01 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;永远怀念&lt;a href=&quot;https://www.luogu.com.cn/user/317974&quot;&gt;rainy_night&lt;/a&gt;同志&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ps: 如果是Coda本人在看的话，搭配Nightyper、信竞之子食用更佳哦&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;bilibili&quot;&amp;gt;
&amp;lt;iframe src=&quot;//player.bilibili.com/player.html?isOutside=true&amp;amp;aid=95707806&amp;amp;bvid=BV1yE411V7Pk&amp;amp;cid=169273356&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;bilibili&quot;&amp;gt;
&amp;lt;iframe src=&quot;//player.bilibili.com/player.html?isOutside=true&amp;amp;aid=76747488&amp;amp;bvid=BV1XJ411d7mA&amp;amp;cid=131271182&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;p&gt;时值十月末，距离NOIP2023还有不短的时间（指20天），也即是信竞生涯的最后20天了。早早起笔退役记，也是为了记录最真实的感受吧。
总结性的话语等比完NOIP再update，先回忆一下。&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;h2&gt;Part1&lt;/h2&gt;
&lt;p&gt;刚上初中的时候，一节信息课上余老师让我们有想报C语言社团的可以找她（对没错当时说的是C语言不是信息竞赛，年幼的我feel confused）。
当时根本不知道C语言是什么，还是lzr拉我去报名。
甚至一开始报错成创客了，甚至该社团的申请书里的“望批”写成了“忘批”。
总之还是机缘巧合开始了编程之旅。&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;h2&gt;Part2&lt;/h2&gt;
&lt;p&gt;刚进C语言社团呢，还是有不少人的，能坐满一个机房，第一节课上的是Scratch……吴老师做的Super Mario还是可以的。
事实上国庆之前都是Scratch，国庆期间花钱《集训》做APP，用的APP Inventor,贪吃蛇Snake（最后还拿了个区二等奖，给分配生加了0.5分）。
总之前半年基本都是在学Scratch和APP，跟OI不能说无关，只能说是毫无关系，算是图形化编程启蒙吧。
直到半年后，C语言社团终于开始教C了！
第一次写#include &amp;lt;cstdio&amp;gt;，第一次写printf(&quot;Hello World!&quot;)，第一次看到运行窗口……当时的新奇和兴奋至今犹记。
——upd 2023.10.31 10:47 语文作文课
教C语言语法其实就劝退一帮人了……
初筛一批之后开始用&lt;a href=&quot;http://oj.ac-code.com/user-home?username=zxw&quot;&gt;ACOJ&lt;/a&gt;，那时候甚至没有申请域名，直接用的IP，A+B Problem首A。
再后来讲到了一些基本的算法和思想了，递归、贪心之类的，人数骤减至5、6个。
也变成了小班教学，转成线上课，开始收费了（到后面就只剩我和&lt;a href=&quot;http://oj.ac-code.com/user-home?username=caoyang&quot;&gt;caoyang&lt;/a&gt;）
当时还是跟&lt;a href=&quot;http://oj.ac-code.com/user-home?username=%E6%B2%88%E7%85%9C%E6%B4%8B&quot;&gt;沈&lt;/a&gt;一起学的，每周一节的线上课，经常和他在QQ上互鉴代码（
然后就在ACOJ里混了些日子，期间考了第一二次CSP，即CSP2020/2021，两次都是同时考J/S，但是都寄了，貌似都是50分左右，但无奈出生于ZJ……
在一些弱省怎么说也有两年的比赛机会了，也挺无奈的。
依稀记得初二升初三那年学OI学上头，买来黄书和深基学语法和基础算法，笔记还特认真（
后来参加了区科技节和七艺的比赛，区科技节寄于笔试，七艺笔试98/100，机试IOI赛制打挂最后拿了个“小童星”的奖（老金还问我怎么拿这么幼稚的奖）&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;h2&gt;Part3&lt;/h2&gt;
&lt;p&gt;到了初三，为了准备分配生，战略放弃OI，但一模二模还是寄。
五月择校的时候还纠结了半天选十四还是学紫，或许在学紫，我的竞赛生涯会大有不同。
中考完一直在玩，初二的学OI狂热劲也没了，ε=(´ο｀*)))。&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;h2&gt;Part4&lt;/h2&gt;
&lt;p&gt;进入高中，分班考的时候报了信竞。
一开始我八班还有lc，yee，小顾。
大江让初中有基础的人到机房3，于是便来到了颓废几十个夜晚的地方。
暑假里信竞组织了集训，3h per day for a week。一开始和机房3的人都不熟，坐到了B4，因为一个含有“zc”字样的验证码认识了&lt;a href=&quot;https://www.luogu.com.cn/user/211648&quot;&gt;J哥&lt;/a&gt;，果然粥p是会互相吸引的。
慢慢又认识了&lt;a href=&quot;https://www.luogu.com.cn/user/602697&quot;&gt;捞湿&lt;/a&gt;，&lt;a href=&quot;https://www.luogu.com.cn/user/339900&quot;&gt;wzj&lt;/a&gt;，&lt;a href=&quot;https://www.luogu.com.cn/user/317909&quot;&gt;xjh&lt;/a&gt;，&lt;a href=&quot;https://www.luogu.com.cn/user/246992&quot;&gt;焦哥&lt;/a&gt;等人，熟络起来了。不过一开始的感觉还是自己太菜了，初中基础过于不牢，在机房被各种暴打。
暑假快结束的时候开始组织刷初赛题了，但还是初赛大失败，只考了S组，58分，然而线64.5……
直接成loser了，捞湿和wzj都是卡线过，J哥J组初赛过了。
那段时间还是挺颓废的，看着他们打模拟赛，看着他们讨论复赛题，看着他们拿二等……而我就在机房颓，不过基本还是学了些东西的，虽然不多但至少比初中的效率高多了。
不过我基本上学完一个算法很快就忘了，也没有那么多心思在课余时间巩固，所以也算是高一摸鱼摸了一年吧，靠着信竞搞来的surf时间还是挺多的。
有一次大江问我学信竞目标是什么，我说信竞当兴趣学的，不在乎成绩如何。
但现在想想，对算法非常感兴趣的阶段似乎已经过了，A题的渴望和快感远不如初二那段时间。
高一快结束的时候，信竞人都走差不多了，机房3还剩10个左右常客。&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;h2&gt;Part5&lt;/h2&gt;
&lt;p&gt;转眼高二了，又颓了一个假期，信竞就集训的时候在搞，其他时间也没什么心思学。
此时我才差不多学完绿及以下的算法，以及少量平衡树等的蓝数据结构。
就这样迎来了人生最后一个OI赛季。
开学之后就投入到了新一轮紧张刺激的初赛备赛，感谢OI为我翘掉了十几场考试。
在追加新角色&lt;a href=&quot;https://www.luogu.com.cn/user/484222&quot;&gt;tyz&lt;/a&gt;之后，机房3彻底成茶话会了（）
初赛考前一天晚上机房十几个人开始神秘仪式，每人拿根pejoy边拜边绕着机房转圈……这也是OI生涯中比较快乐的场面了。
初赛发挥的异常顺利，兴许是前面三年攒下的RP吧，J组78，S组81，正好碰上前几年梦寐以求的加机位，高分飞过。
是哪个省的选手高二才正式参加CSP第二轮？浙江小丑者也！
或许是缺乏经验吧，第二轮崩崩崩，不过也无所谓了，打了就行。
期中考卡在了NOIP前一周，直接成期冢考了……考完期中有了几天运动会的集训（摸鱼）时间，为OI生涯第一次也即是最后一次NOIP磨枪。&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;h2&gt;Part6&lt;/h2&gt;
&lt;p&gt;今年比赛运气相当不错，第二轮J 125/90 S 85/80 NOIP 120/120，混了三个二等（或者说叫省二，好听一点）&lt;/p&gt;
&lt;p&gt;S是T1卡数据点骗分过线。
NOIP卡线我倒是没想到的，往年的二等线貌似没有上三位数的，大概因为今年题简单吧。
T1模拟水题，T2正解并查集暴搜20pts，T3数学题没看，T4正解线段树优化DP，交了贪心上去，喜提0pts。
最终100+20+0+0=120。
说实话出分的时候感觉稳了，出线的时候又是一阵庆幸，毕竟T2的暴力差点因为语法问题（说的就是你，switch-case）没调出来，但总归结果还行。&lt;/p&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;bh&amp;gt;&lt;/p&gt;
&lt;h2&gt;Part7&lt;/h2&gt;
&lt;p&gt;省二落幕，一年前我就知道大概是如此。
不过想想我这三年学OI有多水，这样的结局似乎也不差。
至于收获，有认识了一帮朋友，有在热情减退之前思考和AC的快乐，有翘考试在机房摸鱼的意趣。
我很感谢，很感谢陪伴我中学生涯一半的OI。
但如果重来一次，我想我应该不会选择OI。
这场长达三年的梦，该醒了。&lt;/p&gt;
</content:encoded></item><item><title>CSP-J/S 2023 游记</title><link>https://c0d4.ink/posts/csp-j-s-2023-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://c0d4.ink/posts/csp-j-s-2023-%E6%B8%B8%E8%AE%B0/</guid><description>蒟蒻orz</description><pubDate>Mon, 30 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;10.20&lt;/h2&gt;
&lt;p&gt;考前周五，大蓝书已经看不下去了，遂摆烂一上午&lt;/p&gt;
&lt;p&gt;下午翘考试去机房摸鱼刷你谷讨论区&lt;/p&gt;
&lt;p&gt;晚上直接回家&lt;s&gt;启动&lt;/s&gt;休息，大江还打电话给我讲考试注意事项（&lt;/p&gt;
&lt;p&gt;熬到了23:30才睡，睡前vx祈祷rp++&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;10.21&lt;/h2&gt;
&lt;p&gt;6:30 起床&lt;/p&gt;
&lt;p&gt;8:00 抵达考场&lt;/p&gt;
&lt;p&gt;&lt;s&gt;杭师大缩写居然是ZJNU，是我Normal了&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;s&gt;怎么现场还有成人自考的啊喂&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;8:15 抵达机房，三明治给没让我带进去（&lt;/p&gt;
&lt;p&gt;第一次打复赛感觉还是很新鲜的&lt;/p&gt;
&lt;p&gt;杭师大机房感觉略小、略暗，隔板间距就是课桌间距，真心挤（&lt;/p&gt;
&lt;p&gt;发试题PDF密码还出锅了，福昕阅读器不能开得用Google&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;CSP-J2&lt;/h3&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T1，隔二取一，一眼约瑟夫环，把板子打完之后突然发现是一趟趟从头扫到尾而非环，&lt;strong&gt;心态小崩&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;于是开始手玩小数据找规律，一边推一边烦躁于T1写这么久，&lt;strong&gt;心态小崩&lt;/strong&gt;，又过了40min，才码完代码+调试，O(ans1)&lt;/p&gt;
&lt;p&gt;估分100，实际100&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T2，此时已过去1h，烦躁&lt;/p&gt;
&lt;p&gt;因为考前一周一直在看DP，给整魔怔了，遂先入为主一眼DP&lt;/p&gt;
&lt;p&gt;但是DP太烂，线性DP状态转移方程都没推出来（&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;心态小崩&lt;/strong&gt;，开始打暴力，样例过了就没管了&lt;/p&gt;
&lt;p&gt;考后得知正解贪心……，蚌埠住了，根本没想到贪&lt;/p&gt;
&lt;p&gt;暴力甚至写挂了，bowling&lt;/p&gt;
&lt;p&gt;估分30，实际0&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T3，很快啊，只剩1h力（喜&lt;/p&gt;
&lt;p&gt;**题目描述，一眼大模拟，但是没看懂（当天绝对忌读题），遂打a,b,c均整数部分分&lt;/p&gt;
&lt;p&gt;估分40，实际20（？CCF这题数据有点强）&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T4，最后20min&lt;/p&gt;
&lt;p&gt;乱打了一个BFS骗部分分，并cout&amp;lt;&amp;lt;-1&lt;/p&gt;
&lt;p&gt;此时已经无所谓了，开摆&lt;/p&gt;
&lt;p&gt;估分15，实际5&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;luogu 165  小图灵 130&lt;/p&gt;
&lt;p&gt;CCF 125&lt;/p&gt;
&lt;p&gt;100+0+20+5&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;中午&lt;/p&gt;
&lt;p&gt;和J哥一起吃了顿饭，并分享了T1 O(ans1) 做法&lt;/p&gt;
&lt;p&gt;因为J组就是玩玩，于是心态还行&lt;/p&gt;
&lt;p&gt;趴桌上眯了一会，出发&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;CSP-S2&lt;/h3&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T1，最Joker的一集&lt;/p&gt;
&lt;p&gt;看题干感觉出简单了&lt;/p&gt;
&lt;p&gt;看n&amp;lt;=8一眼暴力枚举&lt;/p&gt;
&lt;p&gt;看样例1，一眼秒n=1时ans=81&lt;/p&gt;
&lt;p&gt;看样例2，？？？？？？？？？？？？？？？？？？&lt;/p&gt;
&lt;p&gt;考场上看了0.5h都没看懂样例2，考后才知道原来同一组里可以一个转一位、一个转两位的……&lt;/p&gt;
&lt;p&gt;题意描述不清且没给样例2解释的CCF是屑，没看懂的我更是屑&lt;/p&gt;
&lt;p&gt;题目没看懂连暴力都没法打，无奈只能输出if(n==1)cout&amp;lt;&amp;lt;81 else cout&amp;lt;&amp;lt;10-n，好歹是有点分&lt;/p&gt;
&lt;p&gt;估分[40,70]，实际60&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T2&lt;/p&gt;
&lt;p&gt;写了个O($n^3$)暴力，很快啊&lt;/p&gt;
&lt;p&gt;估分25，实际25&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T3&lt;/p&gt;
&lt;p&gt;看到长达两页的题干，一眼大模拟，&lt;s&gt;直接被吓晕ambulance抬走&lt;/s&gt;，skip！&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;T4&lt;/p&gt;
&lt;p&gt;乱写了个贪心，max(ceil(a[i]*1.0/b[i])+dfn[i])，假了&lt;/p&gt;
&lt;p&gt;估分[0,15]，实际0&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;luogu 105  小图灵 45  云斗 70  核桃 85&lt;/p&gt;
&lt;p&gt;CCF 85&lt;/p&gt;
&lt;p&gt;60+25+0+0&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;经验不足，时间分配，心态调整（数数加粗字段有几个）&lt;/p&gt;
&lt;p&gt;这些都是大问题&lt;/p&gt;
&lt;p&gt;以及CCF的**题意描述&lt;/p&gt;
&lt;p&gt;以及基础过于不稳&lt;/p&gt;
&lt;p&gt;算了 润去准备NOIP力&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>指针</title><link>https://c0d4.ink/posts/%E6%8C%87%E9%92%88/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E6%8C%87%E9%92%88/</guid><description>指针，存放的是地址，指向地址上的值</description><pubDate>Sun, 17 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;指针定义&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;指针类型&lt;/strong&gt;
如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int a;
int *p; //注意：定义指针时的*属于声明，并不是取值符
p = &amp;amp;a; //&amp;amp;为取地址符，p存放a的地址
所以 *p 等价于 a; //*为取值符
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;指针类型&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;数组指针&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;指向数组的指针，存放数组的地址&lt;/p&gt;
&lt;p&gt;注意：数组名是首地址，&amp;amp;数组名才是数组地址&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;指向数组的类型&lt;/strong&gt; （*指针变量）[数组中&lt;strong&gt;元素个数&lt;/strong&gt;]&lt;/p&gt;
&lt;p&gt;如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int a[5] = { 1, 2, 3, 4, 5 };
int (*p)[5] = &amp;amp;a;
for (int i = 0; i &amp;lt; 5; i++) {
	cout &amp;lt;&amp;lt; (*p)[i] &amp;lt;&amp;lt; &quot; &quot;;
}
输出结果：1 2 3 4 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;函数指针&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;指向函数的指针，存放函数的地址&lt;/p&gt;
&lt;p&gt;注意：函数名就是函数地址&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;指向函数的类型&lt;/strong&gt; （*指针变量)（&lt;strong&gt;函数的参数列表&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int max(int x, int y) {
	return x &amp;gt; y ? x : y;
}
int main() {
	int (*p)(int, int) = max;
	cout &amp;lt;&amp;lt; (*p)(3, 5);    //函数指针的调用，*p即运用取值找到该函数
	return 0;
}	
输出结果：5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;指针操作&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int *p;
p++;   //指针p指向下一个
p--;     //指针p指向上一个
	
int (*p)[5]= &amp;amp;arr;
cout &amp;lt;&amp;lt; *(p+1);  //指向地址（下标）为1的元素，即arr[1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;动态数组&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;极其节省空间，动态分配数组空间&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;动态数组的使用有两种方式：1、指针（如*(p+1)） 2、数组下标（如a[1]）&lt;/p&gt;
&lt;p&gt;指针可以当作数组名，如一级指针p可以当一维数组名，二级指针pp可以当二维数组名&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;动态一维数组&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;int main() {
	int n;
	cin &amp;gt;&amp;gt; n;
	int *p = new int[n];     //此处是将p当作数组名看待，申请一个int型大小为n的空间存放int型的指针p
	for (int i = 1; i &amp;lt;= n; i++) {
		cin &amp;gt;&amp;gt; *(p+i);
    }
	for (int i = 1; i &amp;lt;= n; i++) {
		cout &amp;lt;&amp;lt; *(p+i) &amp;lt;&amp;lt; &quot; &quot;;
    }
	delete[] p;
	return 0; 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入：5
1 2 3 4 5&lt;/p&gt;
&lt;p&gt;输出：1 2 3 4 5&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;动态二维数组&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;运用多级指针实现，主要思路就是把二维数组当作多个一维数组来看待。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;int r = 5;	//用于表示行数
int c = 5;	//用于表示列数
int **arr = new int*[r];	//开辟一块内存来存放每一行的地址
for (int i = 0; i &amp;lt; row; i++)	//分别为每一行开辟内存
    arr[i] = new int[c];
//这是一个r行c列的动态二维数组。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;链表&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://c0d4.ink/2023/09/03/%E9%93%BE%E8%A1%A8/&quot;&gt;链表&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>字符串</title><link>https://c0d4.ink/posts/%E5%AD%97%E7%AC%A6%E4%B8%B2/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E5%AD%97%E7%AC%A6%E4%B8%B2/</guid><description>简单介绍一些OI中常用的字符串操作技巧</description><pubDate>Thu, 14 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;基础操作&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正序&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;for (int i = 0; i &amp;lt; len; i++) //数组第一个数下标为零，最后一个数n下标为n - 1
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;倒序&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;for (int i = len - 1; i &amp;gt;= 0; i--)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;函数&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;输入一行（字符串）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;string s;
getline(cin, s) //cin吞空格，getline不吞
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;字符串拼接&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;string s1, s2;
s1+=s2; //将s2拼接到s1后
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;字符串比较&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;string s1, s2;
s1&amp;lt;s2; //比较s1的字典序是否在s2的字典序前
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;获取字符串长度&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;string s;
s.size();
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;截取&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;string s;
s = s.substr(pos,len) //截取字符串s，从第pos个位置开始len个字符，并返回这个字符串
// 此时s为截取出的字符串

string s1, s2;
s1.insert(pos, s2) //在字符串s1的第pos个字符之前，插入字符串s2，并返回这个字符串

string s1, s2;
s1.find(s2, [pos]) //在字符串s1中从第pos个字符开始寻找s2，并返回位置，如果找不到返回-1（需强制转int），pos可以省略，默认值为0
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;操作&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;strcpy(p, p1) 复制字符串
strncpy(p, p1, n) 复制指定长度字符串
strcat(p, p1) 附加字符串
strncat(p, p1, n) 附加指定长度字符串
strlen(p) 取字符串长度
strcmp(p, p1) 比较字符串
strncmp(p, p1, n) 比较指定长度字符串
strchr(p, c) 在字符串中查找指定字符
strrchr(p, c) 在字符串中反向查找
strstr(p, p1) 查找字符串
strpbrk(p, p1) 以目标字符串的所有字符作为集合，在当前字符串查找该集合的任一元素
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;转类型&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;atoi(p) 字符串转换到 int 整型
atof(p) 字符串转换到 double 符点数
atol(p) 字符串转换到 long 整型
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;检查&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;isalpha() 检查是否为字母字符
isupper() 检查是否为大写字母字符
islower() 检查是否为小写字母字符
isdigit() 检查是否为数字
isspace() 检查是否为空格类型字符
isalnum() 检查是否为字母和数字
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;KMP&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/grcyh/p/10519791.html&quot;&gt;KMP算法详解 - King丨帝御威 - 博客园&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>古早的笔记(自不用)</title><link>https://c0d4.ink/posts/%E5%8F%A4%E6%97%A9%E7%9A%84%E7%AC%94%E8%AE%B0-%E8%87%AA%E4%B8%8D%E7%94%A8/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E5%8F%A4%E6%97%A9%E7%9A%84%E7%AC%94%E8%AE%B0-%E8%87%AA%E4%B8%8D%E7%94%A8/</guid><description>IN MEMORY OF ACOJ</description><pubDate>Thu, 07 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;数据结构&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;栈&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;栈 stack FILO(first in last out)
如一个试管，只有一端可以控制进入输出，且进入输出都只能在栈顶进行，将压入栈顶为push，弹出栈顶为pop&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;手写栈&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

char s[20000];
int n = 0;

char pop() {
    return s[n--];
}
void push(int val) {
    s[++n] = val;
}

int main(void) {
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;STL&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;  
using namespace std;

int main(void) {
    stack&amp;lt;int&amp;gt; s;      // 定义一个栈，栈中元素类型为int
    s.push(5);         // 将元素5压入栈顶
    s.pop();           // 弹出栈顶元素, 但不返回其值
    s.top();           // 返回栈顶元素, 但不删除该元素
    s.size();          // 返回栈中元素的个数
    s.empty();         // 判断栈是否为空，空则返回true，非空返回false

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;括号匹配&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
int main() {
    stack&amp;lt;char&amp;gt; s;
    string str;
    cin &amp;gt;&amp;gt; str;
    for (int i = 0; i &amp;lt; str.length(); i++) {
        if (str[i] == &apos;(&apos;) {
            s.push(&apos;(&apos;);
        } else {
            if (s.empty()) {
                cout &amp;lt;&amp;lt; &quot;no&quot; &amp;lt;&amp;lt; endl;
                return 0;
            }
            s.pop();
        }
    }
    if (s.empty()) {
        cout &amp;lt;&amp;lt; &quot;yes&quot; &amp;lt;&amp;lt; endl;
    } else {
        cout &amp;lt;&amp;lt; &quot;no&quot; &amp;lt;&amp;lt; endl;
    }
     return 0;
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;队列&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;队列 FIFO(first in first out)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;手写队列&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int q[20000];
int head = 1, tail = 0;

int pop() {
    if (head &amp;lt;= tail) {
        return q[head++];
    }
} 

void push(int val) {
    q[++tail] = val;
}

int main(void) {
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;STL&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int main(void) {
    queue&amp;lt;int&amp;gt; q;     // 定义一个队列，队列中元素类型为int
    q.push(5);        // 将元素5入队，放入队尾
    q.pop();          // 队首元素出队，但不返回其值
    q.front();        // 返回队首元素，但不删除该元素
    q.size();         // 返回队列中元素的个数
    q.empty();        // 判断队列是否为空，空则返回true，非空返回false

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;约瑟夫环&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
int main() {
    int n, m;
    queue&amp;lt;int&amp;gt; q;
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; m;
    for (int i = 1; i &amp;lt;= n; i++) {
        q.push(i);
    }
    int cur = 0;
    while (!q.empty()) {
        cur++;
        if (cur == m) {
            cout &amp;lt;&amp;lt; q.front() &amp;lt;&amp;lt; &quot; &quot;;
            q.pop();
            cur = 0;
        } else {
            q.push(q.front());
            q.pop();
        }
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;图&lt;/h3&gt;
&lt;p&gt;拓扑排序（用邻接表）&lt;/p&gt;
&lt;h4&gt;课程安排&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
unordered_map&amp;lt;int, vector&amp;lt;int&amp;gt;&amp;gt; adj;    // 定义个桶（即邻接表），桶的值为整型，位置为一个vector数组 
int inDegree[200000];
int main() {
    int n,m; cin&amp;gt;&amp;gt;n&amp;gt;&amp;gt;m;
    stack&amp;lt;int&amp;gt; s;
    for (int i = 1; i&amp;lt;= m; i++) {       //该for循环为读图操作 
        int x,y;
        cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;
        adj[x].push_back(y); //邻接表操作， 在课程编号为x的课程的vector数组里放入编号为y的课程，化为图即为x -&amp;gt; y 
        inDegree[y] += 1;    //前置课程多了一个，等于该后置课程的入度加一 
    }
    for (int i= 1; i&amp;lt;= n; i++) {
        if (inDegree[i]==0) { //将入度为零的（即没有前置课程）的课程放入栈s中， 
            s.push(i);
        }
    }
    while (!s.empty()) {        //当栈s不为空时
        int cur = s.top();        //cur为当前入度最少的结点 
        cout &amp;lt;&amp;lt; s.top() &amp;lt;&amp;lt; &quot; &quot;;
        s.pop();                //将该入度最少的结点弹出栈，即学习完该课程 
        for (int i = 0; i &amp;lt; adj[cur].size(); i++) {        //该for循环作用为找出在刚刚弹出的结点（即刚学完的课程） 的桶中（即图中该结点指向的结点 ），在弹出该结点后入度为零的结点，将其压入栈顶，表示目前要最先学的课程 
            if (inDegree[adj[cur][i]] - 1 == 0) {
                s.push[adj[cur][i]];
            }
        }
    }
    return 0;
} 
  //注意：有多个结点入度为零时，那栈顶弹出的只有其中之一，接下来栈顶又会压入删去刚才弹出的那个结点后入度为零的，会把最开始的剩余结点覆盖，输出顺序不太对，但没关系，不用管 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;二叉树
相当于一个族谱
想要知道每个家族成员，那就需要遍历&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;有几种不同的遍历方法，用如下二叉树来举例
1
2                   3
4        5          6
7
1、层序遍历
从上往下一层一层的遍历 1 23 456 7&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;前序遍历&lt;/h4&gt;
&lt;p&gt;递归思想，到了无法满足顺序时返回到上一层（下同），顺序是 中左右 1 2 4 5 7 3 6&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
struct TreeNode {
    int l, r;
};

TreeNode tree[200000];

void preOrder(int root) { // void没有返回值 
    if (root == -1) {
        return;
    }
    preOrder(tree[root].r);
    preOrder(tree[root].l);
    printf(&quot;%d &quot;, root);
}

int main() {
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++) {
        scanf(&quot;%d %d&quot;, &amp;amp;tree[i].l, &amp;amp;tree[i].r);
    } 
    preOrder(1);
    return 0;
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;中序遍历&lt;/h4&gt;
&lt;p&gt;顺序是 左中右， 也可以通过所有数在竖列上的位置从左到右遍历，4 2 7 5 1 6 3&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
struct TreeNode {
    int l, r;
};

TreeNode tree[200000];

void preOrder(int root) { // void没有返回值 
    if (root == -1) {
        return;
    }
    preOrder(tree[root].l);
    printf(&quot;%d &quot;, root);
    preOrder(tree[root].r);
}

int main() {
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++) {
        scanf(&quot;%d %d&quot;, &amp;amp;tree[i].l, &amp;amp;tree[i].r);
    } 
    preOrder(1);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;后序遍历&lt;/h4&gt;
&lt;p&gt;顺序是 左右中， 4 7 5 2 6 3 1&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
struct TreeNode {
    int l, r;
};

TreeNode tree[200000];

void preOrder(int root) { // void没有返回值 
    if (root == -1) {
        return;
    }
    preOrder(tree[root].l);
    preOrder(tree[root].r);
    printf(&quot;%d &quot;, root);
}

int main() {
    int n;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++) {
        scanf(&quot;%d %d&quot;, &amp;amp;tree[i].l, &amp;amp;tree[i].r);
    } 
    preOrder(1);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;Hash&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Hash（哈希）
数组下标下可以装字符，数字&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;单词统计&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
//#include &amp;lt;tr1/unordered_map&amp;gt;  //版本问题，比赛中加上
using namespace std;
//using namespace std::tr1;
int main() {
    int n;
    int ans = 0;
    unordered_map&amp;lt;string, int&amp;gt; cnt;    //第一个为元素值 第二个为元素位置
    cin &amp;gt;&amp;gt; n;
    for (int i = 1; i &amp;lt;= n; i++) {
        string tmp;
        cin &amp;gt;&amp;gt; tmp;
        cnt[tmp]++;
        ans = max(ans, cnt[tmp]);
    }
    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; endl;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;字母统计&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
//#include &amp;lt;tr1/unordered_map&amp;gt;
using namespace std;
//using namespace std::tr1;
int main() {
    string s;
    int ans = 0;
    unordered_map&amp;lt;char, int&amp;gt; cnt;
    cin &amp;gt;&amp;gt; s;
    for (int i = 0; i &amp;lt; s.length(); i++) {
        cnt[s[i]]++;
        ans = max(ans, cnt[s[i]]);
    }
    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; endl;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;数字统计&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
//#include &amp;lt;tr1/unordered_map&amp;gt;
using namespace std;
//using namespace std::tr1;
int main() {
    int n;
    cin &amp;gt;&amp;gt; n;
    unordered_map&amp;lt;int, int&amp;gt; cnt;
    for (int i = 1; i &amp;lt;= n; i++) {
        int tmp;
        cin &amp;gt;&amp;gt; tmp;
        cnt[tmp]++;
    }
    cout &amp;lt;&amp;lt; cnt.size() &amp;lt;&amp;lt; endl;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;算法&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;高精度&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;高精度：因为int型范围有限，无法存储大整数，所以用字符串形式输入大整数，再转成int型存入数组中，用数组进行运算&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;加法&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int a[501], b[501], c[502];

int main() {
	string x, y;
	cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;
	int len = max(x.length(), y.length());
	for (int i = len-1; i &amp;gt;= 0; i--) a[len-i] = x[i] - &apos;0&apos;;	 //将x倒着存进数组a,将字符转为整型
	for (int i = len-1; i &amp;gt;= 0; i--) b[len-i] = y[i] - &apos;0&apos;;
	for (int i = 1; i &amp;lt;= len; i++) {
		c[i] += a[i] + b[i];
		c[i+1] = c[i] / 10;		//模拟进位 
		c[i] %= 10;		
	}
	if (c[len+1]) {   //进位可能导致长度加一 
		len++;
	}
	for (int i = len; i &amp;gt;= 1; i--) {    //倒回来输出 
		cout &amp;lt;&amp;lt; c[i];
	}
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;乘法&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int a[5010], b[5010], c[5020];

int main() {
	string x, y;
	cin &amp;gt;&amp;gt; x &amp;gt;&amp;gt; y;
	int lenx = x.length(); int leny = y.length();
	for (int i = lenx-1; i &amp;gt;= 0; i--) a[lenx-i] = x[i] - &apos;0&apos;;
	for (int i = leny-1; i &amp;gt;= 0; i--) b[leny-i] = y[i] - &apos;0&apos;;
	for (int i = 1; i &amp;lt;= lenx; i++) { 	//模拟竖式乘法
		for (int j = 1; j &amp;lt;= leny; j++) {
			c[i+j-1] += a[i] * b[j];     //错位相加
		}
	}
	int len = lenx + leny;    //乘得的积的长度不大于两数长度之和
	for (int i = 1; i &amp;lt;= len; i++) {
		c[i+1] += c[i] / 10;		//模拟进位 
		c[i] %= 10;		
	}
	for (; !c[len] ;) {   	//去掉先导零
		len--;
	}
	for (int i = max(1,len); i &amp;gt;= 1; i--) {    //倒回来输出 
		cout &amp;lt;&amp;lt; c[i];
	}
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;重载板子&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
struct Int{
	int len;
	int a[155];
	void init(){
		len=0;
		memset(a,0,sizeof a);
	}
	Int(){init();}
	Int(int x){
		init();
		if(x==0) ++len;
		while(x){
			a[++len]=x%10;
			x/=10;
		}
	}
	Int operator=(int x){
		init();
		if(x==0) ++len;
		while(x){
			a[++len]=x%10;
			x/=10;
		}
		return *this;
	}
	Int operator=(Int x){
		init();
		len=x.len;
		for(int i=1;i&amp;lt;=len;i++) a[i]=x.a[i];
		return *this;
	}
	void print(){
		for(int i=len;i&amp;gt;0;i--){
			printf(&quot;%d&quot;,a[i]);
		}
	}
};
Int operator+(const Int a,const Int b){
	Int ans;
	ans.len=max(a.len,b.len);
	for(int i=1;i&amp;lt;=ans.len;i++){
		if(i&amp;lt;=a.len) ans.a[i]+=a.a[i];
		if(i&amp;lt;=b.len) ans.a[i]+=b.a[i];
		ans.a[i+1]+=ans.a[i]/10;
		ans.a[i]%=10;
	}
	while(ans.a[ans.len+1]&amp;gt;0) ans.a[ans.len+1]+=ans.a[ans.len]/10,ans.a[ans.len]%=10,ans.len++;
	return ans;
}

Int a[4] = {1,1,1,1};
Int b[4] = {1,999,1,1};

int main() {
	(a[1]+b[1]).print();   //输出为1000 
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;排序&lt;/h3&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;归并&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;主要体现分治思想，复杂度O(nlogn)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int a[MAXN]; int b[MAXN];

void merge(int l, int mid, int r) {
	memset(b,0,sizeof(b));
	int i = l, j = mid+1, k = 0;
	while(i&amp;lt;=mid&amp;amp;&amp;amp;j&amp;lt;=r) {
		if (a[i]&amp;lt;=a[j]) b[++k] = a[i++];
		else b[++k] = a[j++];
	}
	while(i&amp;lt;=mid) b[++k] = a[i++];
	while(j&amp;lt;=r) b[++k] = a[j++];
	for (int i = 1; i &amp;lt;= k; i++) a[l++] = b[i];
}

void mergesort(int l, int r) {
	if (l &amp;lt; r) {
		int mid = l+r&amp;gt;&amp;gt;1;
		mergesort(l,mid);
		mergesort(mid+1,r);
		merge(l,mid,r);
	}
	return;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;快排&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;在数组中随机选择一个数作为标准，比标准小的放标准左边，大的放右边，然后递归分治&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int a[2000000];

void qsort(int a[], int l, int r) {
    int i = l, j = r;
    int p = a[rand() % (r - l + 1) + l];  
             // ① 如何选取基准数（pivot）No.2 a[(r - l) / 2 + l] No.3 a[l]
    while (i &amp;lt;= j) {
        while (a[i] &amp;lt; p) i++;            // ② 与pivot相等的数，要不要交换？
        while (a[j] &amp;gt; p) j--;
        if (i &amp;lt;= j) {                    // ③ 为什么要写if？为什么要加等号？
            swap(a[i++], a[j--]);
        }
    }
    
    if (l &amp;lt; j) qsort(a, l, j);           // ④ 这两条语句什么含义
    if (i &amp;lt; r) qsort(a, i, r);
}

int main(void) {
    int n;

    scanf(&quot;%d&quot;, &amp;amp;n);
    for (int i = 1; i &amp;lt;= n; i++) {
        scanf(&quot;%d&quot;, &amp;amp;a[i]);
    }

    qsort(a, 1, n);

    for (int i = 1; i &amp;lt;= n - 1; i++) {
        printf(&quot;%d &quot;, a[i]);
    }
    printf(&quot;%d\n&quot;, a[n]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;暴力枚举&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;枚举，很暴力！
将数据全部枚举一遍，加以判断或统计
如果全部枚举会超范围，就要考虑更换枚举的元素或剪枝（减少枚举量），即优化枚举&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;循环枚举-烤鸡&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
#define rep(a, i, j) for (int a = i; a &amp;lt;= j; a++)     //利用宏（define）构造语句的功能，简化for循环，前者等价于后者
using namespace std;
int main() {
	int n, a, b, c, d, e, f, g, h, i, j;
	scanf(&quot;%d&quot;, &amp;amp;n);
	int ans = 0;
	rep(a, 1, 3) rep(b, 1, 3) rep(c, 1, 3) rep(d, 1, 3) rep(e, 1, 3)      //优雅的枚举
		rep(f, 1, 3) rep(g, 1, 3) rep(h, 1, 3) rep(i, 1, 3) rep(j, 1, 3) 
			if (a+b+c+d+e+f+g+h+i+j == n) 
				ans++;
	printf(&quot;%d\n&quot;, ans);
	rep(a, 1, 3) rep(b, 1, 3) rep(c, 1, 3) rep(d, 1, 3) rep(e, 1, 3)
		rep(f, 1, 3)rep(g, 1, 3)rep(h, 1, 3)rep(i, 1, 3)rep(j, 1, 3)
			if (a+b+c+d+e+f+g+h+i+j == n) 
				printf(&quot;%d %d %d %d %d %d %d %d %d %d\n&quot;, a, b, c, d, e, f, g, h, i, j);
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;排列枚举-全排列&lt;/h4&gt;
&lt;p&gt;即将每种情况排列，用STL中函数next_permutation（start,end）即可解决
next_permutation函数求的是给定范围中按顺序的下一个排列，若没有下一个排列则返回0&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int a[11];

int main() {
	int n;
	cin &amp;gt;&amp;gt; n;
	for (int i = 1; i &amp;lt;= n; i++) {
		a[i] = i;		//因为next需要数据范围，所以将i赋值到数组，而不是直接用i
	}
	do {				//用do-while是为了使最后一个排序能够输出，while和for需要特判
		for (int i = 1; i &amp;lt;= n; i++) {
			cout &amp;lt;&amp;lt; setw(5) &amp;lt;&amp;lt; a[i];  //场宽5
		}
		cout &amp;lt;&amp;lt; endl;
	} while (next_permutation(a+1, a+1+n));    //指针操作 next所到之处，就是当前次数下的排列
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;递归&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;递归 就是套娃，自己算自己
相当于一个公司，用函数调用手下去算
通过函数中的return不断返回，当不断返回然后不能返回了就输出或达到某种要求输出
一定要有退出条件&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;递归分为两种：数值类和非数值类，
数值类更加简单，根据函数定义直接找出递归边界和递归语句（注意要用if-else连接）
非数值类则需模拟，找规律，再重复数值类步骤&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;斐波那契数列&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
int calc(int a) {
	if (a == 1 || a == 2) {
		return 1;
	}
	return calc(a - 1) + calc(a - 2);
}
int main() {
	int k;
	cin &amp;gt;&amp;gt; k;
	cout &amp;lt;&amp;lt; calc(k) &amp;lt;&amp;lt; endl;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;最大公约数&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
int gcd(int a, int b) {
	if (b == 0) {
		return a;
	}
	return gcd(b, a % b);
}
int main() {
	int a, b;
	cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
	cout &amp;lt;&amp;lt; gcd(a, b) &amp;lt;&amp;lt; endl;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;二叉树最大节点&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
struct TreeNode {
	int val;
	int l, r;
};
vector&amp;lt;TreeNode&amp;gt; tree(200000); 
int getMax(int root) {
	if (root == -1) {
		return INT_MIN;
	}
	int lMax = getMax(tree[root].l);
	int rMax = getMax(tree[root].r);
	int ans = max(lMax, rMax);
	ans = max(ans, tree[root].val);
	printf(&quot;%d &quot;, ans);
	return ans;
}
int main() {
	int n;
	scanf(&quot;%d&quot;, &amp;amp;n);
	for (int i = 1; i &amp;lt;= n; i++) {
		scanf(&quot;%d %d %d&quot;, &amp;amp;tree[i].val, &amp;amp;tree[i].l, &amp;amp;tree[i].r); 
	}
	getMax(1);
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;二分法&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;二分法，就是把一组数砍成两段，中间的点跟所给数比，如果中间数大，那么去左边的数组，如果中间数小，那么去右边的数组&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;排序数组中查找&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
int a[200000];
int n;
int find(int t) {
	int l = 1, r = n;
	while (l &amp;lt;= n) {
		int mid = l + (r - l) / 2;
		if (a[mid] == t) {
			return mid;
		}
		if (a[mid] &amp;lt; t) {
			l = mid + 1;
		}
		if (a[mid] &amp;gt; t) {
			r = mid - 1;
		}
	}
}
int main() {
	cin &amp;gt;&amp;gt; n;
	for (int i = 1; i &amp;lt;= n; i++) {
		cin &amp;gt;&amp;gt; a[i];
	}
	int m;
	cin &amp;gt;&amp;gt; m;
	while (m--) {
		int t;
		cin &amp;gt;&amp;gt; t;
		cout &amp;lt;&amp;lt; find(t) &amp;lt;&amp;lt; endl;
	}
	return 0;
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;DFS&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;又称深度优先搜索或回溯法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;摸球问题&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
int n, m;
void dfs(int x, string path) {
	if (x == n + 1) {
		printf(&quot;%s\n&quot;, path.c_str());
		return;
	}
	for (int i = 1; i &amp;lt;= m; i++) {
		dfs(x + 1, path + (char)(i + &apos;0&apos;));
	}
} 
int main() {
	scanf(&quot;%d %d&quot;, &amp;amp;n, &amp;amp;m);
	dfs(1, &quot;&quot;);
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;全排列&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
int n;
bool v[100];
void dfs(int x, string path) {
	if (x == n + 1) {
		printf(&quot;%s\n&quot;, path.c_str());
		return;
	}
	for (int i = 1; i &amp;lt;= n; i++) {
		if (v[i]) {
			continue;
		}
		v[i] = true;
		dfs(x + 1, path + (char)(i + &apos;0&apos;));
		v[i] = false;
	}
} 
int main() {
	scanf(&quot;%d&quot;, &amp;amp;n);
	dfs(1, &quot;&quot;);
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>计算机基础知识</title><link>https://c0d4.ink/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/</guid><description>翻蓝书整理出来的知识点，草率且不严谨，仅供参考</description><pubDate>Wed, 06 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;计算机常识&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;电子管——&amp;gt;晶体管——&amp;gt;集成电路——&amp;gt;超大规模集成电路&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1946 美国宾夕法尼亚大学第一台电子计算机 ENIAC&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;冯·诺依曼核心理论&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;二进制&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存储程序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;五大部件 (I/O，运算器ALU，存储器，控制器)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;图灵 英国人&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;计算机系统&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F.png&quot; alt=&quot;计算机系统&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;硬件系统&lt;/h3&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;速度：Cache &amp;gt; 内存 &amp;gt; 外存&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;软件系统&lt;/h3&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;操作系统&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;桌面OS&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;类UNIX&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务器OS&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;UNIX&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Linux&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;计算机语言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;计算机指令： 操作码 &amp;amp; 操作数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;机器语言&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;汇编语言&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;高级语言&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;编译性  C/C++  Pascal&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解释性  PHP  Java  JavaScript  Python  Ruby&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;面向对象&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;纯面向对象  Smalltalk&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;混合型  C++&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;面向过程  C&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;计算机网络&lt;/h2&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;局域网 (LAN)&lt;/strong&gt;      &lt;strong&gt;城域网 (MAN)&lt;/strong&gt;      &lt;strong&gt;广域网 (WAN)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;Internet&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Internet采用的协议为TCP/IP，即 传输控制协议(Transmission Control Protocol，TCP) 与 网络协议(Internet Protocol，IP)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;OSI协议&lt;strong&gt;7&lt;/strong&gt;层    TCP/IP协议&lt;strong&gt;4&lt;/strong&gt;层&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;TCP/IP&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;应用层    Telnet (远程登录)  FTP (文本传输)   E-mail&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输层    TCP  UDP&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络层    IP&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;接口层&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;IP地址&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;识别Internet上节点的地址，IPV4为32位(4组*8位)，IPV6位128位(8组*16位)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;IPV4    4个不大于255的数组成&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A类地址： 1~126&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;B类地址：128~191&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;C类地址： 192~223&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;回环地址： 127.0.0.1&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;域名&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;字符形式的IP地址 (避免记忆4个无意义数)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;格式：    开头.主机名.主机类别.国家名 &lt;em&gt;(可不要)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;eg.  域名：oj.ac-code.com&lt;/p&gt;
&lt;p&gt;对应 IP：    121.40.233.101&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;域名由域名系统 (Domain Name System，DNS) 管理&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h4&gt;电子邮件&lt;/h4&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SMTP  发邮件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MIME&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;POP3  收邮件&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>数据结构</title><link>https://c0d4.ink/posts/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</guid><description>常用数据结构</description><pubDate>Tue, 05 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;树&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;此处尤指二叉树Binary Tree&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;基本性质&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;性质1： 第i层上最多有$2^{i-1}$个节点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性质2： 深度为k(根节点深度为1)的二叉树最多有$2^k-1$个节点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性质3： $n_0=n_2+1$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性质4： n个节点的完全二叉树的深度为 $\lfloor \log_2^n \rfloor$+1&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性质5： n个节点的二叉树的叶子节点个数最多有$\frac{n+1}{2}$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;遍历&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这个都会吧（&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前序： 根左右  波兰&lt;/p&gt;
&lt;p&gt;中序： 左根右  投影&lt;/p&gt;
&lt;p&gt;后序： 左右根  逆波兰&lt;/p&gt;
&lt;p&gt;已知 &lt;strong&gt;前中、中后&lt;/strong&gt; 都可画出唯一树&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;图&lt;/h2&gt;
&lt;h3&gt;特殊图&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;欧拉图：
从任意点开始，都能找到一笔画
起点和终点重合&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;半欧拉图:
只有两个奇点（度为奇数的点）
一个奇点开始，一个奇点结束&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;哈密尔顿图：
经过每个点1次，遍历完全部点&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;链式前向星&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;void addEdge(int u, int v, int w) {
	edge[++tot].v = v;
	edge[tot].w = w;
	edge[tot].next = head[u];
	head[u] = tot;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>位运算</title><link>https://c0d4.ink/posts/%E4%BD%8D%E8%BF%90%E7%AE%97/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E4%BD%8D%E8%BF%90%E7%AE%97/</guid><description>有一种东西是计算机易于理解 但人难以李姐的</description><pubDate>Sun, 03 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;优先级&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;运算符&lt;/th&gt;
&lt;th&gt;优先级&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;（）&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;! ~&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;* / %&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+ -&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt; &amp;lt;= &amp;gt;= &amp;gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;amp;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;^&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;or&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;特殊用法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;取反(~)改变符号位 取反保持正负性需加负号 ~-a or -~a&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a ^ a = 0&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a ^ 0 = a&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a ^ -1 = ~a&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;交换a,b的值： a ^= b ^= a ^= b&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>对拍</title><link>https://c0d4.ink/posts/%E5%AF%B9%E6%8B%8D/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E5%AF%B9%E6%8B%8D/</guid><pubDate>Sun, 03 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/EdisonBa/p/13509379.html&quot;&gt;C++ 对拍详解&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;The Sample&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;n个数选k个，和为sum的方案数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;暴力程序&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int n, k;
int ans;
int sum;

void dfs(int x, int start) {
	if (x == k+1) {
		if (sum == n) ans++;
		return;
	}
	for (int i = start; sum+i*(k-x+1) &amp;lt;= n; i++) {
		sum+=i;
		dfs(x+1,i);
		sum-=i;
	}
}

int main() {
	
	freopen(&quot;data.in&quot;,&quot;r&quot;,stdin);
	freopen(&quot;dfs.out&quot;,&quot;w&quot;,stdout);
	
	cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; k;
	dfs(1,1);
	cout &amp;lt;&amp;lt; ans;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;待测程序&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int n,k,f[201][7];  //f[k][x] k 分成 x 份 ={f[k-1][x-1],f[k-x][x]}

int main(){
	
	freopen(&quot;data.in&quot;,&quot;r&quot;,stdin);
	freopen(&quot;dp.out&quot;,&quot;w&quot;,stdout);
	
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; k;
    for (int i=1;i&amp;lt;=n;i++) {f[i][1]=1;f[i][0]=1;}for (int x=2;x&amp;lt;=k;x++) {f[1][x]=0;f[0][x]=0;}  // 边界，为了防止炸，我把有0的也处理了
    for (int i=2;i&amp;lt;=n;i++)
        for (int x=2;x&amp;lt;=k;x++)
            if (i&amp;gt;x) f[i][x]=f[i-1][x-1]+f[i-x][x];
            else f[i][x]=f[i-1][x-1];
    cout&amp;lt;&amp;lt;f[n][k];
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;DataMaker&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int main() {
	freopen(&quot;data.in&quot;,&quot;w&quot;,stdout);
	srand(time(0));
	cout &amp;lt;&amp;lt; rand()%193+7 &amp;lt;&amp;lt;&quot; &quot;&amp;lt;&amp;lt; rand()%4+2;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Checker&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int main() {
	int n = 100;
	while(n--) {
		system(&quot;DataMaker.exe&quot;);
		system(&quot;dfs.exe&quot;);
		system(&quot;dp.exe&quot;);
		if (system(&quot;fc dfs.out dp.out&quot;)) {
			break;
		}
	}
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>数论（OI）</title><link>https://c0d4.ink/posts/%E6%95%B0%E8%AE%BA/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E6%95%B0%E8%AE%BA/</guid><description>常用的一些小小数论知识</description><pubDate>Sun, 03 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;模运算&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;$a%b = a-b*floor(\frac ab)$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;费马小定理&lt;/p&gt;
&lt;p&gt;$a^{p-1} % p=1$&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;最小公倍数&amp;amp;最大公约数&lt;/h2&gt;
&lt;p&gt;(a,b)表示最大公约数&lt;/p&gt;
&lt;p&gt;[a,b]表示最小公倍数&lt;/p&gt;
&lt;p&gt;$(a,b)*[a,b] = ab$&lt;/p&gt;
&lt;p&gt;辗转相除&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (a % b==0) return b;
else return gcd(b, a % b);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;质数&lt;/h2&gt;
&lt;p&gt;筛法&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (int i = 2; i &amp;lt;= n; i++) {
    if (is_prime[i])
        for (int j = 2*i; j &amp;lt;= n; j+=i) is_prime[j]=false; //筛去当前素数的倍数
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;欧拉函数 $\phi$&lt;/p&gt;
&lt;p&gt;求互质(公约数只有1的两个整数)个数&lt;/p&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h2&gt;快速幂&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;在幂指数过大的情况下，快速幂运算&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;int power(int a, int n) {
  int tp = 1;
  while (n) {
    if (n &amp;amp; 1) tp = 1ll * tp * a % mod;
    a = 1ll * a * a % mod, n &amp;gt;&amp;gt;= 1;
  }
  return tp;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;分治&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;将$a^{100}$化成$a^{50}*a^{50}$,递归处理&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

typedef long long ll;

ll a, b, m;
int getRes(ll a, ll b, ll m) {
	if (b == 0) return 1;
	if (b % 2 == 1) {
		return a * getRes(a, b - 1, m) % m;
	} else {
		ll mul = getRes(a, b / 2, m);
		return mul * mul % m;
	}
}

int main() {
	cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; m;
	cout &amp;lt;&amp;lt; getRes(a, b, m); 
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;h3&gt;迭代&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;将幂指数作二进制数位运算&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;
typedef long long ll;

ll a, b, m;

int main() {
	cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; m;
	ll ans = 1, cur = a;
	while (b &amp;gt; 0) {
		if (b &amp;amp; 1) ans = ans * cur % m;
		cur = cur * cur % m;
		b &amp;gt;&amp;gt;= 1;
	}
	cout &amp;lt;&amp;lt; ans;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>链表</title><link>https://c0d4.ink/posts/%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://c0d4.ink/posts/%E9%93%BE%E8%A1%A8/</guid><description>当需要插入或删除数据结构中某些元素时，用链表比数组方便得多，访问某一元素时则链表就是个dd。</description><pubDate>Sun, 03 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;注意：链表中的每个元素在使用前都要申请一个空间（new）并指向NULL(-&amp;gt;next = NULL)，即初始化操作
由于链表不能访问某一元素，所以每次操作前都要从头开始（p =head），并用j记录节点下标&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;单链表基本框架&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;%E5%8D%95%E9%93%BE%E8%A1%A8%E6%A8%A1%E6%8B%9F.jpg&quot; alt=&quot;单链表模拟&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;结构体&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;struct Node {                 
	int data;
	Node *next;   //自引用，构建链表，链表中每个结点有两部分，数据域data和指针域next，data存值，next指向下一个结点
} *head, *p, *r;	       //头指针，指针，尾指针
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;建表&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;void set(int a[], int n) {  //尾插 
	head = new Node; head -&amp;gt; next = NULL; r=head;    //刚开始是r和head是在一起的，便于尾插操作
	for (int i = 1; i &amp;lt;= n; i++) {
		p = new Node;
		p -&amp;gt; data = a[i];
		p -&amp;gt; next = NULL;
		r -&amp;gt; next = p;         //将p插到r后面
		r = p;                      //r后移
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;%E5%8D%95%E9%93%BE%E8%A1%A8%E6%8F%92%E5%88%A0.jpg&quot; alt=&quot;单链表插删&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;插入&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;void insert(int a[], int pos, int val) {    //详见模拟图
	p = head;		      //从头开始
	int i = 0;
	while (p != NULL &amp;amp;&amp;amp; i &amp;lt; pos - 1) {
		p = p -&amp;gt; next;      //p指向下一个结点
		i++;
	}
	Node *s; 
	s = new Node;
	s -&amp;gt; data = val;
	s -&amp;gt; next = p -&amp;gt; next;
	p -&amp;gt; next = s; 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;删除&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;void del(int a[], int pos) {      //详见模拟图
	p = head;
	int i = 0;
	while (p != NULL &amp;amp;&amp;amp; i &amp;lt; pos - 1) {
		p = p -&amp;gt; next;
		i++;
	}
	Node *s;
	s = new Node;
	s = p -&amp;gt; next;
	p -&amp;gt; next = s -&amp;gt; next;
	delete[] s;
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;打印&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;void print() {                                      
	p = head -&amp;gt; next;
	while (p -&amp;gt; next != NULL) {
		cout &amp;lt;&amp;lt; p -&amp;gt; data &amp;lt;&amp;lt; &quot; &quot;;
		p = p -&amp;gt; next;
	}
	cout &amp;lt;&amp;lt; p -&amp;gt; data &amp;lt;&amp;lt; endl;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;主函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;int main() {
	int n;
	cin &amp;gt;&amp;gt; n;
	int a[200000];
	for (int i = 1; i &amp;lt;= n; i++) {
		cin &amp;gt;&amp;gt; a[i];
	}
	set(a, n); 
	int m;
	cin &amp;gt;&amp;gt; m;
	for (int i = 1; i &amp;lt;= n; i++) {
		if (a[i] == m) {
			del(a, i);
		}
	}
	print();
	delete[] p;     //防内存泄漏
  	delete[] head;
	return 0;
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;双向链表模拟&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;%E5%8F%8C%E5%90%91%E9%93%BE%E8%A1%A8%E6%A8%A1%E6%8B%9F.jpg&quot; alt=&quot;双向链表模拟&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;循环链表模拟&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;%E5%BE%AA%E7%8E%AF%E9%93%BE%E8%A1%A8%E6%A8%A1%E6%8B%9F.jpg&quot; alt=&quot;循环链表模拟&quot; /&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>