openSUSE Leap 15.2 中文字体配置

openSUSE Leap 15.2 安装好以后,还需要配置一下才能使中文字体可用。

我使用的中文字体是Noto Sans系列,如果需要其他中文字体请替换为相应的字体。

首先是Konsole中的中英文混排。需要在/etc/sysconfig/fonts-config里面重新定义Monospace字体:

PREFER_MONO_FAMILIES=”Cascadia Code:Noto Sans Mono CJK SC”

然后是浏览器中的英中日文混排,需要在/etc/sysconf/fonts-config里面重新定义Sans Serif字体:

PREFER_SANS_FAMILIES=”Noto Sans:Noto Sans SC:Noto Sans JP”

最后是在$HOME/.config/config/fonts.conf里面加入自己喜欢的字体配置:

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig> 
<!-- Fuck Helvetica -->
 <match>
    <test name="family">
        <string>Helvetica</string>
    </test>
    <edit binding="same" mode="assign" name="family">
        <string>Noto Sans</string>
    </edit>
 </match>
 <!-- Fuck Arial -->
 <match>
    <test name="family">
        <string>Arial</string>
    </test>
    <edit binding="same" mode="assign" name="family">
        <string>Noto Sans</string>
    </edit>
 </match>
 <!-- Fuck Courier New -->
 <match>
    <test name="family">
        <string>Courier New</string>
    </test>
    <edit binding="same" mode="assign" name="family">
        <string>Noto Sans</string>
    </edit>
 </match>
 <!-- Fuck Microsoft YaHei -->
 <match>
    <test name="family">
        <string>Microsoft YaHei</string>
    </test>
    <edit binding="same" mode="assign" name="family">
        <string>Noto Sans</string>
    </edit>
 </match>

 <!-- /etc/fonts/conf.d/49-sansserif.conf fall back fonts to sans-serif if non-generic family -->
 <!-- so we manually add monospace family here -->
 <alias>
      <family>Cascadia Code</family>
      <default>
        <family>monospace</family>
      </default>
 </alias>
 <!-- by default fontconfig assumes any unrecognized font is sans-serif, so -->
 <!-- the fonts above now have /both/ families.  fix this. -->
 <!-- note that "delete" applies to the first match, so only sans-serif is deleted -->
 <match>
     <test compare="eq" name="family">
         <string>sans-serif</string>
     </test>
     <test compare="eq" name="family">
         <string>Cascadia Code</string>
     </test>
     <edit mode="delete" name="family"/>
 </match>
</fontconfig>

[解题报告] Campus Bike II

动态规划方式求解。

状态定义:dp[i][s] = 前i个人在s状态下,选择自行车的最优值

注意,动态规划中的状态必须描述全局。如果定义i是第i个人,j是第j辆车的话,dp[i][j]并不能描述全局情况,因此不具有“无后效性”。

所以用dp[i][s]来描述状态,s用来代表当前所有车的状态 (availability)。例如bit(s, j) 代表第j辆车是否可用。

dp[0][s] = min(dist[0][j](如果bit(s, j)==1) or INF (如果bit(s, j)==0)), for j = [0, m)

dp[i][s] = min(dp[i][s], dp[i-1][prev]+dist[i][m], prev=(set(s, m, 0))), for j = [0, m)

总体复杂度为O(n * (1 << m) * m)。

Notes on the regular expressions

The regular expression syntax we are using here is BRE. ERE and PCRE is covered at the end of this article.

First, we need to know how to express a SINGLE character.

  • Literals: a, A, b, B
  • Enumeration as bracket expressions: [a-zA-Z], [0-9], [^a-z]. Bracket expressions can further embed characters
    • Character classes: [:alnum:] numbers or letters
    • Collating symbols: [.ch.]
    • Equivalence class: [=e=]
  • Numbers: \d
  • Spaces, tabs, carriages: \s
  • Letters OR Numbers OR Understore: \w, equivalent to [[:alnum:]_]
    • \W is the negated version of \w
  • Dot .: matches any character
  • Zero-length Anchors: ^(start), $(end), and \b(word boundaries)
    • \B is the negated version of \b

Second, metas that expresses the preceding character that repeats.

  • *: appear zero or more times
  • \{n\}: match specfic number of times.
    • For example, \{2\} matches appearing twice, \{2, 8\} matches appearing from twice to eight times, and so on.

Third, grouping and back references:

  • \(\) and \$GRPNUM, match the previously matched group. $0 means the entire match.

As for ERE, it only slightly differs from BRE.

  • ERE does not have groups and back references.
  • ERE uses {n, m} to serve as appearances.
  • ERE provides ?, +, |, () for regex compositions.

Notes on GNU Assembler

First, a few handy notations.

  • .(Single dot): Evaluates to the assembly position at the beginning of the current instruction.
  • ..(Double dots): Evaluates to the beginning of the current section.

Second, a few useful pesudo-instructions:

  • .ascii Define an ascii string.
  • .asciz Define an ascii string ending with ‘\0’ (null-terminated string)

Third, the call interface for system calls:

# Read-only data section
.section .rodata
msg:        .ascii  "Hello from syscall!\n"
msg_len     =       .-msg

.section .text
.globl _start
_start:
    # Syscalls on x86_64: syscall
    # Syscall Number: %rax
    # Argument list: %rdi, %rsi, %rdx, %r10, %r8, %r9, <stack>
    # Return value: %rax
    # Example:
    movq $1, %rax
    movq $1, %rdi # file descriptor: stdout
    movq $msg, %rsi # message string char*
    movq $msg_len, %rdx # message length
    syscall
    # Syscalls on i386: int 80h
    # Syscall Number: %eax
    # Argument list: %ebx, %ecx, %edx, %esi, %edi, %ebp, <stack>
    # Return Value: %eax
    movl $4, %eax # The syscall no is different from x86_64
    movl $1, %ebx # file descriptor: stdout
    movl $msg, %ecx # message string char*
    movl $msg_len, %edx # message length
    int $0x80
    
    # Syscall exit()
    movq $60, %rax
    movq $0, %rdi
    syscall

To build executables from .s files with two shell commands:

$ as <ASM-FILE>.s -o <OBJ-FILE>.o
$ ld <OBJ-FILE>.o -o <BIN-FILE>.out

If you would like to make the glibc library calls, you have to make a few changes to your program. For example, the entry of your program is now main instead of _start, and you need to use gcc instead of as to link your program. Note that when calling a function with va_args such as printf, you need a small trick for va_args to avoid crash by setting the %al register to 0.

# printf.s
# Calling printf() in assembly
    .section .rodata
msg:        .asciz "Hello, world!\n"

    .section .text
    .globl main
    .extern printf
main:
    # Library call arguments:
    # Argument lists: rdi, rsi, rdx, rcx, r8, r9, <stack>
    movq $msg, %rdi
    # Magic for va_args (0==no magic, to prevent a crash)
    mov $0, %al
    call printf
    
    # Exit
    movq $0, %rdi
    call exit

To compile this snippet, run the following:

$ gcc printf.s -o printf.out

Reviving VMJP on Linux

I became a bit nostalgia this Christmas weekend and decided to revive my childhood game: Vantage Master Japan on openSUSE Tumbleweed. This post describes how I did that.

First, the game checks a few registry keys upon start. Specifically, it won’t start if the following key is missing:


Windows Registry Editor Version 5.00
[HKEY_USERS\S-1-5-21-0-0-0-1000\Software\Falcom]
[HKEY_USERS\S-1-5-21-0-0-0-1000\Software\Falcom\Fsetup]
"DisplayName"="Fsetup"
"Path"="[YOUR_VMJP_LOCATION]"
"VMJ"="[YOUR_VMJP_LOCATION]\\VMJ\\"
"VMJP"="[YOUR_VMJP_LOCATION]\\VMJP\\"

After adding the registry keys, I was be able to start the game with wine, and everything in the game works except there was no background music. The version of wine is wine-5.0-rc2.

After checking the wine output, I noticed the following error log:

0009:fixme:adpcm:ADPCM_StreamOpen We don’t support encoding yet

This log is printed by the file msadp32.c, which is related to audio output. This file corresponds to the WINEPREFIX/drive_c/windows/system32/msadp32.acm binary, which is essentially a DLL file.

It looks like wine hasn’t implemented this function in their built-in DLL. So we can replace it with a native one bundled in Windows. I downloaded one from here. Its sha256 checksum is fc836f9e08e8879ea3d3bb9bd6ecc7404af810399ec7dead6d72d70b6a4df6a0.

So I simply replace the msadp32.acm in the WINEPREFIX and use winecfg to prioritize native msadp32.acm over the built-in one. Thereafter, the game is able to play the background music on Wine.

 

[解题报告] NOIP 2006 金明的预算方案

本题是一道经典的带依赖背包题。每个主件可以有零个,一个,或两个附件可以依赖。因此在计算子问题“用j元购买主件i”时,需要考虑以下几种情况:
1. 不购买主件i: f[i-1][j]
2. 购买主件i,不购买任何附件:f[i-1][j-price[i]] + price[i] * importance[i]
3. 购买主件i,购买附件1。(方程略)
4. 购买主件i,购买附件2。(方程略)
5. 购买主件i,购买附件1和2。(方程略)
取以上五种情况的最大值即可计算f[i][j],再按普通0-1背包处理即可。

本题第一次写错是只计算了f[i][N]到f[i][price[i]]范围内的子问题,没有计算f[i][0]到f[i][price[i]-1]的子问题。事实上就算买不起第i个主件,仍然可以求得只购买前i-1个主件的最大价值。

TODO:用树形DP解题

[解题报告] NOIP 2006 作业调度方案

这道水题花了我好几个小时……哎。所以觉得有必要写一下解题报告。

利用m台机器加工n个工件,每个工件都有m道工序,保证这m个工序正好使用到这m台机器,但是每个工序所用的时间不一样。给定一个工件加工序列,该序列满足以下要求:

  1. 每个工件按顺序进行加工,进行第i道工序必须完成前i-1道工序。
  2. 同一时刻每台机器最多加工一个工件。
  3. 若某机器有多个空余时间段进行加工,选取时间最靠前的时间段。

给定的工件加工序列的每一步指定了工件编号,工序编号和机器编号。

那么我们需要在指定的机器上找到一个可用的时间段。一个可用的时间段必须满足以下要求:

  1. 开始时间大于前一步工序的结束时间
  2. 时间段的长度大于工序长度

使用一个数组来保存每一个机器的时间占用情况,数组的每个元素保存了一个合法的工序。从头到尾扫描这个数组,并找到起始时间最早的合法空隙。最后结果即为最后一道工序的结束时间。

本题我出错的地方在于将第i-1步工序的结束时间计算成了前i-1步工序的时长之和,但是实际上这些工序不是从头到尾连在一起的,中间可能隔了其他工件的工序,所以需要在每一步计算时对前一步工序的结束时间进行更新。

例程:https://pastebin.com/Pc7zuVaT

EVE世界服低等死亡空间攻略

EVE Online(星战前夜)是一款多人MMO游戏,以其入门难度高而知名。之所以说它入门困难,并不是因为操作特别复杂或者战斗特别困难,而是完成了新手教学之后玩家很容易陷入迷茫之中:接下来我到底该干点什么?

当然你可以选择按部就班的挖矿或者做任务培养声望。但是总有渴望冒险和刺激的玩家希望以更快的方式进阶,为了一夜暴富愿意冒着船蛋双亡的风险。我就是这样的一位玩家。

如果你和我如下的想法不谋而合:

– 希望迅速积攒起千万级别乃至亿级别的ISK,快速开上T2级别高级护卫舰

– 愿意独自行动,不想被军团或者公司要求束缚

– 在高安等和低安等地区活动

那么这篇攻略就是为你准备的。

首先你需要准备如下东西和知识:

– 装配任意族T1护卫舰,需要多个高能量槽,一个装扫描仪其他装武器,建议DPS达到100以上为佳

– 学会核心探针扫描,能将未知宇宙信号(Cosmic Signatures)定位并跃迁至该处

如果你都能做到,恭喜你可以开始刷死亡空间了。

死亡空间类似副本,在不定位置和时间刷新。其难度由易至难分为1/10到10/10不同种类。击败副本内最终Boss或摧毁目标建筑物后即可获得奖励。奖励大小看脸,最值钱的是混血护卫蓝图(blueprint),一张可值上亿ISK,也可用于自行制造混血护卫舰。小一点的有海盗势力装备,价值千万至百万ISK不等。如果脸黑就只有安慰奖:监察官的个人物品(Overseer’s Personal Effects)。

下面是注意事项:

  1. 死亡空间是不直接显示在地图上的,因此需要我们自己从未知宇宙信号中扫描出来。如果你想用同一条船扫描和攻略死亡空间,那么请计算好由于装配扫描探针造成的DPS损失。若开T1护卫舰,建议只刷四族1/10。T1护卫舰刷2/10会*非常*吃力,需花大量时间风筝,效率低。
  2. 1/10和2/10都只在0.9或者1.0的高安全区出现,因此扫描时可以直接跳过安全等级低于0.9的星系。顺便说下,低于0.9的星系扫出来的大多是3/10及以上级别的死亡空间。
  3. 人多的高安星系往往在死亡空间刷新后会有人第一时间扫描到并进入刷怪,由于部分死亡空间有钥匙机制,只有第一个清怪的人可以拿到头目钥匙并用它进入加速轨道(钥匙是一次性使用)。所以如果进入死亡空间后发现一地的残骸可以直接退了。建议前往人烟稀少的高安星系扫描,本地频道人数最好在五人以内。
  4. 四族地盘的死亡空间各不相同。加达里是古斯塔斯海盗,艾玛是血袭者,米玛塔尔是天使集团,盖伦特是天蛇和萨沙,请务必针对刷到的死亡空间里面的怪属性调整舰船装备。

以艾玛血袭者2/10为例:

在艾玛帝国区某安全系数为0.9的星系,本地人数为2,打开扫描仪发现未知信号,探针定位后确定为血袭者2/10死亡空间“血袭者血汗工厂”。

跃迁到指定位置后进入加速轨道,清理里面的怪后继续进入加速轨道。如果怪没清干净,加速轨道是不能启动的。如此这般三次,到第四层为最后一层,击败Boss“血袭者护卫监察官”后,拾取残骸即可获得奖励。因奖励也是需要放进货舱里的,请时刻注意自己货舱容量。

 

 

 

如何在日本以外地区购买及阅读日亚Kindle电子书

最近想读一些日语电子书来进一步提升自身日语水平。经李先生博客推荐,发现booth.pm站可以买到一些轻小说和短篇作品,比较适合初学者阅读。

不过我认为理想情况还是能够在日亚自由购买及阅读Kindle版的日语书籍。我在天朝亚马逊及加拿大亚马逊的Kindle购书经验发现,Kindle帐号名是全球统一的,仅仅通过注册邮箱不同而对帐号进行区分。这也就意味着,无论是安卓平台还是PC/Mac平台,只要你用不同的邮箱在不同的地区分别注册Kindle帐号,就可以用同一个Kindle应用登录各地区的Kindle商店。

那么剩下的问题还有两个。首先,仅仅注册一个日亚帐号是无法直接购买Kindle书籍的,必须在设定中指定所在地区为日本才行。为了解决这个问题,我注册了Tenso转运,用转运提供的地址作为自身日本地址后,就可以用Visa或万事达信用卡买书了。由于网上有传闻说如果使用海外IP购买太多书籍会导致日亚帐号被封,我每次买书前都会先挂一个东京的VPN以取得日本IP。

第二个问题是如何在设备上多开Kindle软件。安卓平台提供了App Cloner应用,克隆好Kindle应用后,分别用不同的邮箱帐号登录,就可以在一台机器上享受不同Kindle地区的电子书了。

Enjoy!

初春

这几天思绪很杂乱,作业又没有写完。上完课时,忽觉阳光洒面,暖意融融。纵然时间紧迫,若不趁此走走,便是辜负这美好的时光了。

心想何必回宿舍呢,于是欣然停好车背包便走。园子很大,足够我折腾的了。待至水木清华,才发现冬天真的已经过去。青草嫩芽自不必说,山上几种不知名的花儿也欢笑着开着,粉的,白的,果然漂亮。俯身近观,只见雄蕊雌蕊依依然,三片花瓣围着,不由歆羡大自然的创造伟力,这种对称而又不对称的美。
信步登顶,山后别有洞天。上次见时这里还是天寒地冻,霜枝冰封。而今日已然碧波荡漾,游人如织。且依稀听得水响。这时才发现自清亭和闻亭原来如此之近,回头望望,两位大师的风姿悉收眼底,这大概也只有在这儿才能做到吧。拱手作别,继续前行。
前方便是西阶,我不愿又去礼堂前面,便从西阶的后面绕路,记得去年大雪,面前的小溪也是冰冻三尺,当时自己正纠结于期末考试,学过的嘈杂东西正在脑子里纠缠不清,忽然见到这溪,还曾拍砖砸冰。叹气,便取了石子轻破水面,惊动了游鱼。
又至工字厅,真是久历风霜的建筑……一砖一瓦都有一段故事。从墙下走过,纱窗不知是什么材料,已然变脆如细钢丝,轻掰便碎。忽然抬眼见到王观堂先生的纪念碑,顿感学校真是福地,步履所至处处有先贤,又觉自身渺小,在园子里呆了许久竟浑然不知,实在该死。近读碑文,又感此事过于复杂,还是以少写为上策。
转身离开,前方已没有道路,于是折返再上山。不知走了多远,见一碑上书“清华儿女 华夏英烈”,下面有几束花放着,才忆起次日便是清明,可惜手中无花,于是随手采了几朵聊表心意。又回想曾见过的西南联大纪念碑,有一面写满了参军及牺牲的英雄名字,这便是过去中华青年之精英,民族未来及希望所在,只盼时代虽然不同,青年风骨依旧刚毅坚卓。下面是一条小路,还记得去年纷飞的大雪,我在此路上深一脚浅一脚地走着,差点被雪埋掉的悲惨场景,那时的雪真是多得可以游泳了。而当前却有大旱,祈愿世界之安宁。
到达西操时,已是日薄西山暮将近,一照晚霞披虹彩。
些许疲惫,于是顺便躺下望天看云。以前的记忆又浮上心头,那真的是很久很久以前了……也是在这样的夕阳下,我也曾躺在家乡中学的操场上,躺在家附近的公园长凳上望天。彼此之心绪,恍如隔世,然而在外人看来不过都是如此,我真的成长了么?这么困难的事情,我自己也不知道。视野中有风筝悠然飞过,不由得微微一笑。环视四周,跑步,足球,风筝,蒙楼,又回想起中午时无意中看到的重信房子的资料,她为女儿起名为“命”,实在再恰当不过了。这种对汉字的体悟力,令我由衷感叹。
周围有些冷了,我背起书包,起身走人。
起风了,夜已将至。