注意 encrypt = decrypt,加解密相同。本质是 XOR
流密码,但 key 不是简单循环——有一个递增步长的索引调度(step starts at 1,
increments after each full cycle)。
Python 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
defgizcrypt_decrypt(ct, key): klen = len(key) x, k = 1, -1 e = 101# ord('e') plain = bytearray() for b in ct: k += x if k >= klen: k = 0 x += 1 if x >= klen: x = 1 plain.append(key[k % klen] ^ b ^ e) returnbytes(plain)
defkey_index_seq(length, klen=11): seq = [] x, k = 1, -1 for _ inrange(length): k += x if k >= klen: k = 0; x += 1 if x >= klen: x = 1 seq.append(k % klen) return seq
seq = key_index_seq(len(ct)) groups = {i: [] for i inrange(11)} for i, kpos inenumerate(seq): groups[kpos].append(ct[i])
key = [] for pos inrange(11): best = None best_score = -9999 for k in alphabet: plain = bytes(k ^ c ^ 101for c in groups[pos]) score = sum(4if b in (32,101,116,97,111) else 2ifchr(b).isalpha() or b in (44,46,39) else 1if32 <= b < 127else -10 for b in plain) if score > best_score: best_score = score best = k key.append(best)
root = TrieNode() for word inopen('/usr/share/dict/words'): w = word.strip().lower() iflen(w) >= 6: node = root for ch in w: node = node.children.setdefault(ch, TrieNode()) node.is_word = True
# 2. 获取网格 r = sess.get(f'{BASE}/generate.php') match = re.search(r'<pre>(.*?)</pre>', r.text, re.DOTALL) grid = [list(line.strip().lower()) for line inmatch.group(1).strip().split('\n') if line.strip()] ROWS, COLS = len(grid), len(grid[0])
# 3. 8 方向搜索(用 Trie 实时剪枝) DIRS = [(0,1),(0,-1),(1,0),(-1,0),(1,1),(1,-1),(-1,1),(-1,-1)] found = {} # word -> (start_r, start_c)
for r inrange(ROWS): for c inrange(COLS): for dr, dc in DIRS: node, last_word, last_len = root, None, 0 for step inrange(max(ROWS, COLS)): nr, nc = r + dr*step, c + dc*step ifnot (0 <= nr < ROWS and0 <= nc < COLS): break ch = grid[nr][nc] if ch notin node.children: break node = node.children[ch] if node.is_word: word = ''.join(grid[r+dr*s][c+dc*s] for s inrange(step+1)) if word notin found: found[word] = (r, c)
BASE = 'https://www.wechall.net/en/challenge/training/programming/knapsaak' COOKIES = {'WC': '...'}
defparse_problem(text): items = [] meta = {} for line in text.strip().split('\n'): if'='notin line: continue k, v = line.split('=', 1) k, v = k.strip(), v.strip() if k in ('Items', 'Sum', 'Stock', 'Level'): meta[k] = int(v) else: items.append((k, int(v))) # (name, price) return items, meta['Items'], meta['Sum'], meta['Stock']
defsolve(items, need_count, need_sum, stock): n = len(items) prices = [p for _, p in items] names = [n for n, _ in items] # 按价格降序排列(剪枝效果更好) order = sorted(range(n), key=lambda i: -prices[i]) sp = [prices[i] for i in order]
memo = {} defdfs(idx, ri, rs): if ri == 0and rs == 0: return [0] * (n - idx) if idx == n or ri < 0or rs < 0: returnNone key = (idx, ri, rs) if key in memo: return memo[key] # 剪枝:剩余件数超出库存限制 if ri > stock * (n - idx): memo[key] = None; returnNone # 剪枝:剩余金额超出价格范围 min_p, max_p = min(sp[idx:]), max(sp[idx:]) if rs < ri * min_p or rs > ri * max_p: memo[key] = None; returnNone
p = sp[idx] for qty inrange(min(stock, ri, rs // p) + 1): sub = dfs(idx + 1, ri - qty, rs - qty * p) if sub isnotNone: memo[key] = [qty] + sub return memo[key] memo[key] = None returnNone
qs = dfs(0, need_count, need_sum) if qs isNone: returnNone # 按原始顺序还原 quants = [0] * n for i, orig_idx inenumerate(order): quants[orig_idx] = qs[i] # 拼接答案:qtyName... return''.join(str(quants[i]) + names[i] for i inrange(n) if quants[i] > 0)
deffrom_base(s, charset, base): value = 0 table = {ch: i for i, ch inenumerate(charset[:base])} for ch in s: value = value * base + table[ch] return value
defto_base(n, charset, base): if n == 0: return charset[0] out = [] while n: n, r = divmod(n, base) out.append(charset[r]) return''.join(reversed(out))
deffrom_base(s, charset, base): table = {ch: i for i, ch inenumerate(charset[:base])} v = 0 for ch in s: v = v * base + table[ch] return v
defto_base(n, charset, base): if n == 0: return charset[0] out = [] while n: n, r = divmod(n, base); out.append(charset[r]) return''.join(reversed(out))
Mr. Bacon is back with an advanced Bacon cipher. The encoder uses a
non-standard mapping where the case pattern depends on the letter's
position in the alphabet (a-m vs n-z), not just uppercase/lowercase.
letters = [c for c in encoded_text if c.isalpha()] bits = ''.join('0'if c.lower() < 'n'else'1'for c in letters if c.isupper()) answer = ''.join(chr(int(bits[i:i+5], 2) + 65) for i inrange(0, len(bits), 5))