Typora 主题 | 99% 还原 CCF NOI 系列赛事题面

· · 科技·工程

使用 Typora 出模拟赛题的你,是否觉得可用的主题太丑,与 CCF 题面风格完全不符?

我(和 DeepSeek、DeepWiki)开发了一个 Typora 主题,几乎完全还原了 CCF NOI 系列赛事题面(大部分参数是我手动尝试并于官方 pdf 对比得到的)。

因为我觉得 Consolas 更好看,所以代码块使用了 Consolas 字体。

:::info[主题源码]

/* ========================================  
   名称: CCF 官方题目样式 + tuack 表格  
   基于: cnoi-statement-generator/templates/cnoi/typst/main.typ  
   ======================================== */  

/* ========== 全局重置 ========== */  
* {  
  margin: 0;  
  padding: 0;  
  box-sizing: border-box;  
}  

/* ========== 基础样式 ========== */  
body {  
  font-family: "Times New Roman", "SimSun", "STSong", "宋体", serif;  
  font-size: 12pt;  
  line-height: 1.6;  
  font-weight: normal;          /* ← 修复:0 → normal (400) */  
  color: #000000;  
  background: #ffffff;  
  margin: 0 auto;  
  padding: 2rem;  
  max-width: 850px;  
  text-align: justify;  
}  

/* ========== 标题 ========== */  
h2 {  
  font-family: "SimHei", "Microsoft YaHei", "Helvetica Neue", "Arial", sans-serif;  
  font-size: 18pt;  
  font-weight: 500;  
  text-align: center;  
  margin: 1em 0 0.5em 0;  
  padding: 0;  
  border: none;  
  color: #000000;  
}  

h3 {  
  font-family: "SimHei", "Microsoft YaHei", "Helvetica Neue", "Arial", sans-serif;  
  font-size: 13pt;  
  font-weight: 500;  
  text-align: left;  
  margin: 1.25em 0 0.5em 0;  
  padding: 0 0 0 1em;  
  border: none;  
  color: #000000;  
}  

/* ========== 正文段落 ========== */  
p {  
  margin: 0;  
  line-height: 1.6;  
  text-align: justify;  
  text-indent: 2em;  
}  

/* ========== 列表(通用) ========== */  
ul, ol {  
  list-style: none;  
  padding-left: 0 !important;  
  margin: 0;  
  counter-reset: ol-counter;  
}  

li {  
  margin: 0 0 0 2em;  
  line-height: 1.6;  
  position: relative;  
  padding-left: 1em;  
}  

li p {  
  margin: 0 !important;  
  padding: 0 !important;  
  text-indent: 0 !important;  
}  

/* ========== 无序列表符号(按嵌套层级) ========== */  
ul > li::before {  
  content: "•";  
  position: absolute;  
  left: 0;  
  top: 0;  
}  
ul ul > li::before { content: "–"; }  
ul ul ul > li::before { content: "∗"; }  
ul ul ul ul > li::before { content: "·"; }  

/* ========== 有序列表编号 ========== */  
ol > li {  
  counter-increment: ol-counter;  
}  
ol > li::before {  
  content: counter(ol-counter) ".";  
  position: absolute;  
  left: 0;  
  top: 0;  
}

/* ========== 加粗(NOI 官方风格) ========== */  
strong, b {  
  font-family: "SimHei", "Microsoft YaHei", "黑体", sans-serif;  
  font-weight: bold !important;  
  /* 着重号:仅对 CJK 字符视觉效果好 */  
  -webkit-text-emphasis: filled dot;  
  text-emphasis: filled dot;  
  -webkit-text-emphasis-position: under right;  
  text-emphasis-position: under right;  
}  

/* 加粗内的代码不加着重号 */  
strong code, b code,  
code strong, code b,  
pre strong, pre b {  
  -webkit-text-emphasis: none !important;  
  text-emphasis: none !important;  
  font-family: "Consolas", "SimSun", "宋体", monospace;  
}

/* ========== 内联代码 ========== */  
code {  
  font-family: "Consolas", "SimSun", "宋体", monospace;  
  font-size: 12pt !important;  
  background-color: transparent;  
  padding: 0;  
  border-radius: 0;  
  color: #000000;  
}  

/* ========== 代码块 ========== */  
pre {  
  background-color: transparent;  
  border: 0.4pt solid #0000ff;  
  border-radius: 0;  
  padding: 2pt 3pt 4pt 3pt;    /* ← 修正:6pt-4pt=2pt, 9pt-4pt=5pt */  
  overflow-x: auto;  
  margin: 10pt 0;  
  font-size: 12pt !important;  
  line-height: 1.6;               /* ← 修正:对应 Typst 每行 box inset 4.25pt×2 */  
  font-family: "Consolas", "SimSun", "宋体", monospace;  
  white-space: pre;  
}  

pre code {  
  background-color: transparent;  
  padding: 0;  
  color: #000000;  
  font-family: inherit;  
  font-size: inherit;  
}  

/* ========== 仅 cpp 有语法高亮 ========== */  
pre[lang="cpp"] .cm-s-inner .cm-comment { color: #00ff00; font-style: italic; }  
pre[lang="cpp"] .cm-s-inner .cm-string  { color: #000000 !important; font-weight: bold !important; }  
pre[lang="cpp"] .cm-s-inner .cm-keyword { color: #bf0040; font-weight: bold; }  
pre[lang="cpp"] .cm-s-inner .cm-type,  
pre[lang="cpp"] .cm-s-inner .cm-variable-3 { color: #bf0040; font-weight: bold; }  
pre[lang="cpp"] .cm-s-inner .cm-meta { color: #bf0040; font-weight: bold; }  
pre[lang="cpp"] .cm-s-inner .cm-operator { color: #000000; font-weight: normal; }  
pre[lang="cpp"] .cm-s-inner .cm-def,  
pre[lang="cpp"] .cm-s-inner .cm-variable,  
pre[lang="cpp"] .cm-s-inner .cm-variable-2,  
pre[lang="cpp"] .cm-s-inner .cm-builtin,  
pre[lang="cpp"] .cm-s-inner .cm-atom,  
pre[lang="cpp"] .cm-s-inner .cm-number { color: #000000; font-weight: normal; }  
pre[lang="cpp"] .cm-s-inner .cm-string-2 { color: #000000; font-weight: normal; }  

/* ========== 除 cpp 外所有语言全黑 ========== */  
pre:not([lang="cpp"]):not([lang="c++"]) .cm-s-inner span {  
  color: #000000 !important;  
  font-weight: normal !important;  
  font-style: normal !important;  
}  

/* 行号 */  
.CodeMirror-linenumber {  
  color: #808080;  
  font-size: 10pt;  
}

/* ========== 数学公式 ========== */  
.math {  
  font-family: "Times New Roman", "STIXGeneral", "Cambria Math", serif;  
  font-size: 1em;  
}  

.math-inline {  
  font-family: inherit;  
  vertical-align: middle !important;  
  line-height: 1.6 !important;  
}  

.math-display, .katex-display, .MathJax_Display {  
  margin: 0 !important;  
  overflow-x: auto;  
  text-align: center;  
  line-height: 1.6 !important;  
}  

.math, .katex, .MathJax,  
.md-math-block, .md-inline-math,  
.math-display, .katex-display {  
  text-indent: 0 !important;  
}  

/* ========== 链接 ========== */  
a {  
  color: #2c7da0;  
  text-decoration: none;  
}  

a:hover {  
  text-decoration: underline;  
}  

/* =============================================  
   tuack 三线表(默认)  
   对应 Typst:  
     stroke: (x, y) => (  
       left: if x > 0 { .4pt },  
       bottom: 2pt,  
       top: if y == 0 { 2pt } else if y == 1 { 1.2pt } else { .4pt },  
     )  
     align: center + horizon  
   ============================================= */  

table {  
  border-collapse: collapse;  
  width: auto;  
  margin-left: auto !important;  
  margin-right: auto !important;  
  margin-top: 9pt;  
  margin-bottom: 6pt;  
  border-top: 2pt solid #000;  
  border-bottom: 2pt solid #000;  
  border-left: none;  
  border-right: none;  
  font-family: "Times New Roman", "SimSun", "STSong", "宋体", serif;  
  font-size: 12pt;  
}  
table th,  
table td {  
  padding: 4pt 8pt;  
  text-align: center;  
  vertical-align: middle;  
  text-indent: 0;  
  border-left: none;  
  border-right: none;  
  border-top: none;  
  border-bottom: none;  
}  

/* 非首列左侧 0.4pt 竖线 */  
table th + th,  
table td + td {  
  border-left: 0.4pt solid #000;  
}  

/* 表头底部 1.2pt */  
table thead th {  
  border-bottom: 1.2pt solid #000;  
  font-weight: bold;  
}  

/* 数据行间 0.4pt */  
table tbody tr + tr td {  
  border-top: 0.4pt solid #000;  
}  

/* =============================================  
   等宽边框表(用 <div class="cnoi-info-table"> 包裹)  
   对应 Typst: #set table(stroke: 0.3pt)  
   ============================================= */  

.cnoi-info-table table {  
  border: 0.3pt solid #000;  
}  

.cnoi-info-table table th,  
.cnoi-info-table table td {  
  border: 0.3pt solid #000;  
  text-align: left;  
  vertical-align: bottom;  
}  

.cnoi-info-table table th + th,  
.cnoi-info-table table td + td {  
  border-left: 0.3pt solid #000;  
}  

.cnoi-info-table table thead th {  
  border-bottom: 0.3pt solid #000;  
  font-weight: normal;  
}  

.cnoi-info-table table tbody tr + tr td {  
  border-top: 0.3pt solid #000;  
}  

p:has(.md-inline-math-container),  
p:has(.math-inline),  
p:has(mjx-container) {  
  text-align: left !important;  
}  

/* ========== 打印 / PDF 导出 ========== */  
@media print {  
  * {  
    -webkit-print-color-adjust: exact !important;  
    print-color-adjust: exact !important;  
  }  

  @page {  
    size: A4;  
    margin: 1.6cm;  
  }  

  body {  
    margin: 0;  
    padding: 0;  
    max-width: none;  
  }  

  /* --- 分页控制 --- */  
  table, pre, figure {  
    page-break-inside: avoid;  
    break-inside: avoid;  
  }  

  h2, h3, h4, h5, h6 {  
    page-break-after: avoid;  
    break-after: avoid;  
  }  

  p {  
    orphans: 3;  
    widows: 3;  
  }  

  img {  
    page-break-inside: avoid;  
    break-inside: avoid;  
  }  

  /* --- 列表打印 --- */  
  ul, ol {  
    list-style: none;  
    padding-left: 0 !important;  
    margin: 0;  
  }  

  /* --- 数学公式打印 --- */  
  .math-display, .katex-display, .MathJax_Display {  
    margin: 0 !important;  
    overflow-x: auto;  
    text-align: center;  
    font-weight: 300 !important;  
    line-height: 1.6 !important;  
  }  

  /* --- 三线表线条加粗(解决 PDF 中线条不可区分) --- */  
  table {  
    border-top: 2.5pt solid #000 !important;  
    border-bottom: 2.5pt solid #000 !important;  
  }  

  table thead th {  
    border-bottom: 1.5pt solid #000 !important;  
  }  

  table tbody tr + tr td {  
    border-top: 0.75pt solid #000 !important;  
  }  

  table th + th,  
  table td + td {  
    border-left: 0.75pt solid #000 !important;  
  }  

  /* --- 等宽边框表打印 --- */  
  .cnoi-info-table table,  
  .cnoi-info-table table th,  
  .cnoi-info-table table td {  
    border-width: 0.5pt !important;  
  }  
}

:::

使用教程:

题目名称需要使用二级标题,“题目描述”等需要使用三级标题。

目前已知的问题有:

排列游戏生成的 pdf:https://www.luogu.com.cn/problem/U674531。

注:本项目部分参考了 CNOI Statement Generator 中的数据,如有侵权请联系我删除。