情報の坩堝的な

メモがわりに記事を書きます。たまにQiitaにも同じ内容を投稿します。

二色成型キーキャップ SPKCS67B レビュー

はじめに

愛用しているFILCO Minila AirのキーキャップをSPKCS67Bに変更してみたのでレビュー

外観

f:id:prio_victor:20200727113533j:plain
外観

印字されている文字が丸っこく、柔らかな見た目です。 なんとなく、レトロな雰囲気を醸し出しており個人的には好みです。

キーキャップの違い

形状

上記の二点が通常のキーキャップと異なります。

キーキャップの高さ

f:id:prio_victor:20200727113541j:plain
キーキャップ形状の違い

結構違います。 私は割と指が長めなのでパームレストなしでも利用できていますが、元々のキーボードの土台の高さと合わせると最上段のキーは机から4.5cmほどの高さになります。 パームレストも検討された方がいいかもしれません。 また、元のキーキャップと新しいものを併せて使用するような用途は不可です。

キートップの角度

もともと付属しているキーキャップは場所によって、キートップの角度が違います。

f:id:prio_victor:20200727120517j:plain
通常のキーキャップ:曲線を描くような角度設計
f:id:prio_victor:20200727120521j:plain
SPKCS67B:ほぼ直線的な角度設計

慣れればどちらでも問題ないですが、このような違いもあります。

質感

元のキーキャップはマットっぽい仕上げ。対してSPKCS67Bは少し光沢があリます。 実際に使っていただかいないとなんとも表現しづらいのですが、元のキーキャップはサラサラ、SPKCS67Bはしっとり。 加えて、キートップがすり鉢状になっているため指に吸い付くようなフィット感もあります。

個人的には交換後の質感の方が好みです。

キープリント

ダブルFnキーと組み合わせることで様々な入力が可能となるのがMinila Airの一つの特徴です。 通常のキーキャップでは側面に印刷されていますが、こちらのキーキャップにはその印字がありません。

f:id:prio_victor:20200727113537j:plain
通常キーキャップの印字
f:id:prio_victor:20200727113545j:plain
SPKCS67Bの印字

まずは通常のキーキャップで操作に慣れた方がいいかもしれません。

FJキーのあれがない

ホームポジションを死守する上で必須の突起がありません。

ないと不便なので瞬間接着剤でキー上に突起を作ってみました。 良い感じです。 f:id:prio_victor:20200727113530j:plain

総評

前述までの違いを踏まえた上で、いい商品だと思いました。

AGC 045 A Xor Battle 解説

はじめに

  • 当日
    • 20:55 よーし、AGCがんばるぞー
    • 21:00 コンテスト開始
    • 21:30 なんもわからん。コンテスト終わったら解説読むか
  • 翌日以降: 誰も解説してくれないんだが...?

その後、おおよそ理解したのでメモ。

事前知識

XOR関連

XOR(排他的論理和)とは

詳細はWikiで。 要点は以下の真理値表(ここで⊕は問題文にならってXORに対応)

ABA⊕B
000
011
101
110

特に、

  • ABが同じ: 0
  • ABが異なる: 1
  • XORを偶数回操作すると元に戻る: $A \oplus B \oplus B=A$

です。

自分自身が逆元である

単位元を0とすると、二進数表記のAに対する逆元はA自身です。 例えば、$A=00101$とします。自分自身とのXORをとってみましょう。

$$A \oplus A=00000$$

詳しい証明などはこちらを参照してください。

ベクトルの線型結合

線形従属・線形独立

線形代数の基礎知識、線形従属・線形独立の理解が必要です。 Wikiさんとか理数アラカルトさんに譲ります。

ここでは、具体例を交えながら簡単に解説します。 3次元空間を考えます。 ベクトル${\bf v}_{1}, {\bf v}_{2}$があるとしましょう。ただし、${\bf v}_{1}=(0, 0, 1)^\top, {\bf v}_{2}=(0, 1, 0)^\top$とします。 このとき 、${\bf v}_{3}$が${\bf v}_{1}, {\bf v}_{2}$の線形和で表せるかを考えます。

  • case 1: ${\bf v}_{3}=(0, 1, 1)^\top$

→単純に${\bf v}_{1}+{\bf v}_{2}$で${\bf v}_{3}$で表すことができます。 このとき、${\bf v}_{3}$は${\bf v}_{1}, {\bf v}_{2}$と線形従属な関係にあります。

  • case 2: ${\bf v}_{3}=(1, 0, 0)^\top$

→このケースはいくら${\bf v}_{1}, {\bf v}_{2}$をこねくりまわしても、${\bf v}_{3}$を表現することができません。 このとき、${\bf v}_{3}$は${\bf v}_{1}, {\bf v}_{2}$と線形独立な関係にあります。

続いて、XOR演算でこの特性を確認していきましょう。

XORにおける従属関係の確認方法

よく見ると、先程3次元で定義していたベクトル${\bf v}$というのは、二進数表記の整数に見えますね(見えてください)。

つまり、${\bf v}_{1}=(0, 0, 1) \rightarrow e_1=001, {\bf v}_{1}=(0, 1, 0) \rightarrow e_2=010$に見えます。 このとき 、ある整数の二進数表記$v$が、$e_1, e_2$のXORのみで表現できるかはどのように確認できるでしょうか?

  • case 1: $v=011$

→単純に$e_1 \oplus e_2$で表すことができます。すなわち、$v$は既存の基底と従属な関係にある。

  • case 1: $v=110$

→$e_1, e_2$をこねくり回しても表現できません。すなわち、$v$は既存の基底と独立な関係にある。ただし、追加で$e_3=100$という基底があれば表現可能です。

また、値の大きい基底から順番に、基底の最上位bitが$v$で立っているかを確認することで、従属関係を確認できます*1

具体的なコードは以下。

base = [1, 2]
v = int(input())

for e in sorted(base, reverse=True):
    # print('v  : {:2d} {:05b}'.format(v, v))
    # print('e  : {:2d} {:05b}'.format(e, e))
    # print('e^v: {:2d} {:05b}'.format(v ^ e, v ^ e))
    # print('-'*16)
    v = min(v, e ^ v)
# print('v  : {:2d} {:05b}'.format(v, v))

if v == 0:
    print('従属!')
if v > 0:
    print('独立!')

※print前のコメントアウトを消すと変数の細かな動きを確認できます。

ここで、minが掃き出し処理に相当します*2

動作例

3
v  :  3 00011
e  :  2 00010
e^v:  1 00001
----------------
v  :  1 00001
e  :  1 00001
e^v:  0 00000
----------------
v  :  0 00000
従属!

また、重要な知見として、計算結果の変数vは、入力値vを表現するために追加で必要な基底にあたります

解説

発想と方針

  • 発想
    • $A_{1:i-1}$に関係なく、$A_i$を$A_{i+1:N}$のXORで表現できなければ、0さんは詰み
    • $A_i$を$A_{i+1:N}$で表現できなくする動作をしたら、1さんの勝ち
  • 方針
    • 後ろから$A_i$を$A_{i+1:N}$で表現できるかチェック
      • $A_{i+1:N}$の基底で貼る空間に$A_i$が収まっている(従属)か?
    • 表現できるなら、0さん1さん関係なくpass
    • 表現できない場合
      • 0さん: $A_i$を使用(=基底を追加)
      • 1さん: $A_i$を使わないことで勝利が確定

ACコード

前項の発想と方針を実装すると以下になります。

def solve():
    base = []
    for a, s in zip(A[::-1], S[::-1]):
        # print(f'a: {a}, s: {s}')
        # for i, y in enumerate(base):
        #     print('base{:d} {:3d}: {:05b}'.format(i, y, y))
        x = a
        for y in sorted(base, reverse=True):
            x = min(x, x ^ y)
        if x:
            if s == "0":
                # print('=>add {:3d}: {:05b}'.format(x, x))
                base.append(x)
            else:
                return 1
    return 0


t = int(input())
for _ in range(t):
    n = int(input())
    *A, = map(int, input().split())
    S = input()
    # print(f'A: {A}, S: {S}')
    print(solve())
    # print('-'*32)

※print前のコメントアウトを消すと変数の細かな動きを確認できます。

こんな感じ。baseで表現できなければ、baseにaddされていきます。

A: [2, 3, 4, 5, 6, 7], S: 111000
a: 7, s: 0
=>add   7: 00111
a: 6, s: 0
base0   7: 00111
=>add   1: 00001
a: 5, s: 0
base0   7: 00111
base1   1: 00001
=>add   2: 00010
a: 4, s: 1
base0   7: 00111
base1   1: 00001
base2   2: 00010
a: 3, s: 1
base0   7: 00111
base1   1: 00001
base2   2: 00010
a: 2, s: 1
base0   7: 00111
base1   1: 00001
base2   2: 00010
0

わからないこと

従属関係を確認する際に、appendした順に比較を行うこと(つまり、sorted(base, reverse_True) -> base)でもACとなるのはなぜか?

おわりに

AGC難しい...。 間違っている箇所などあればご指摘ください。

参考資料

*1:こちらなどを参考にしました

*2:XORをとったときに$v$が小さくなる→ある基底$e$の最上位bitが$v$上で1であるため

OverleafでVimiumとVimキーバインドが衝突して使えない問題

はじめに

数時間前にOverleafでVimキーバインドが使えることを知った。 基本的に日本語編集とVimキーバインドの相性は良くないが、コピーとか矩形選択は便利なので使おうとするもノーマルモードに戻れない。 調べてみるとChrome拡張機能Vimiumと衝突してるみたい。

VimiumをOverleaf上で使用できなくして、キーバインドの設定を行ったら快適になったのでメモ。

Overleaf上でVimiumを無効化

  1. サイトを訪れる
  2. Vimiumアイコンをクリックし、以下の画像の状態で保存
    f:id:prio_victor:20200605233848p:plain
    Vimiumの無効化

以上。 これでOverleaf上のプロジェクトで正常にVimキーバインドが使用できる。

.vimrc的な設定

普段から使っているキーバインドはそのまま利用したい。例えばjjでEscとか。

tampermonkyという拡張機能を利用する。

  1. サイトを訪れる
  2. Tampermonkyアイコンをクリック、新しくユーザースクリプトを作成する
  3. 以下のコードを貼り付け、保存(公式のコードを一部加工)
// ==UserScript==
// @name         Overleaf Editor Custom VIM Keybindings
// @namespace    http://tampermonkey.net/
// @version      0.1
// @match        https://www.overleaf.com/project/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    // poll until editor is loaded
    const retry = setInterval(() => {
        if (window._debug_editors === undefined) return
        clearInterval(retry)
        // get current editor instance
        const editor = window._debug_editors[window._debug_editors.length -1]
        // vim keyboard plugin
        const vimKeyboard = window.ace.require("ace/keyboard/vim")
        // add custom keybindings - insert mode applies on insert
        vimKeyboard.Vim.map("jj", "<Esc>l", "insert")
        // set the modified keyboard handler for editor
        editor.setKeyboardHandler(vimKeyboard.handler)
        console.log("Custom key bindings applied")
    }, 100)
})();

Tampermonkyが正常に動作すれば、上記のコードがOverleafを開いた際に自動で実行されjjでEscができるようになる。

参考資料