# -*- coding: utf-8 -*- """Assemble per-problem teaching data (题目 statement + 参考答案 + 解析要点) for CSP04 lesson 01. Reference code read from C++代码/CSP04/01/*.cpp (GBK).""" import json, io from pathlib import Path ROOT = Path(__file__).resolve().parent.parent.parent.parent CODE_DIR = ROOT / 'C++代码' / 'CSP04' / '01' def read_code(fname): for enc in ('gbk', 'gb18030', 'utf-8'): try: p = CODE_DIR / fname if not p.exists(): return '' return io.open(p, encoding=enc).read().strip() except Exception: continue return '' # 每题:题目在问什么 + 关键点(解析) PROBLEMS = { 'S0401P1': { 'title': '小杨的回文串', 'statement': '给定一个只含英文字母、大小写混合的字符串,问三件事:①把所有字母统一转小写后,它是不是回文串(是Yes/否No);②原串里有多少个大写字母;③原串里有多少个小写字母。回文就是正读倒读一样,如 abba、abcba。', 'key_points': '先统计后转换(统计的是原串的大写/小写个数);大写字母 +32 = 小写字母;用双指针 l/r 向中间夹,发现一次不相等就判否;三行输出顺序是 回文结果/大写个数/小写个数。', 'code_file': '小杨的回文串.cpp', }, 'S0401P2': { 'title': '小杨有序去重', 'statement': '给定一份非降序的成绩单(相邻可能相等),去掉连续的重复成绩,得到“出现过的不同成绩”列表。用双指针在数组上原地完成:慢指针 j 指向已保留部分的末尾,快指针 i 向后扫,遇到 a[i] ≠ a[j] 就把 a[i] 复制到 a[j+1]。输出两行:去重后的列表;不同成绩的个数。', 'key_points': '前提是“有序”,只去相邻重复;比较对象是 a[j](保留区末尾),不是 a[i-1];j 从 1 开始、i 从 2 开始(第一个数无条件保留);n 最大 1e5,必须一遍扫完。', 'code_file': '小杨有序去重.cpp', }, 'S0401P3': { 'title': '小杨的进制数位', 'statement': '把十进制数 n 转换成 k 进制(2≤k≤16),并统计表示里的字符构成:①k 进制表示(超过 9 的数位用大写 A~F 表示 10~15);②表示中数字字符(0~9)的个数;③表示中字母字符(A~F)的个数。', 'key_points': '除 k 取余、余数倒着拼(out = S[余数] + out);查表 “0123456789ABCDEF”;n=0 要特判输出 0;统计的是 k 进制表示里的字符,不是十进制原数。', 'code_file': '小杨的进制数位.cpp', }, 'S0401P4': { 'title': '小杨的幸运数字', 'statement': '有些正整数的二进制表示里恰好只有 1 个 1(如 1=1、2=10、8=1000),这样的数叫“幸运数”,也就是 2 的幂。给 n 个正整数,统计:①这 n 个数里幸运数的个数;②这 n 个数的二进制表示中 1 的总个数。', 'key_points': '对每个数单独数它的 1 的个数(cnt1 每轮要清零);sum 累计的是“1 的个数”,cnt 累计的是“满足条件的数”,别混;1(=2^0)也是幸运数;进阶可用 n&(n-1)==0 判断/__builtin_popcount 数 1。', 'code_file': '小杨的幸运数字.cpp', }, 'S0401P5': { 'title': '小杨的报数游戏', 'statement': 'n 个小朋友围成一圈,编号 1~n。从 1 号开始沿顺时针从 1 报数,报到 k 的小朋友出列,出列者下一位重新从 1 报数……直到全部出列。按出列顺序输出编号(约瑟夫问题)。', 'key_points': '数组 arr[i] 记状态(0 在场/1 出列);只有 arr[idx]==0 的人才报数;报满 k 出列后 cnt 归零、p--;idx 越界就回绕 idx>n→idx=1;边界 k=1 依次出列 1 2 3…n。', 'code_file': '小杨的报数游戏.cpp', }, } out = {} for pid, meta in PROBLEMS.items(): code = read_code(meta['code_file']) out[pid] = { 'key': pid + ' ' + meta['title'], 'title': meta['title'], 'statement': meta['statement'], 'key_points': meta['key_points'], 'code_file': meta['code_file'], 'ref_code': code, } dest = ROOT / '.claude' / 'memory' / 'temp' / 'problems_meta.json' dest.parent.mkdir(parents=True, exist_ok=True) dest.write_text(json.dumps(out, ensure_ascii=False, indent=2), encoding='utf-8') print('SAVED ->', dest) for pid, meta in out.items(): print(pid, 'ref_code_len=', len(meta['ref_code']))