如题!
本次更新的内容有:
提交详情页面更新!换成了正方形的测试点信息,非常帅!
个人博客首页的更新!改变了页面风格,右侧对齐了火焰图,特别帅!
博客详情页的更新!同样,右边加了个人信息,让页面更丰富,贼帅!
dsv4f 太屌了!
如题!
本次更新的内容有:
提交详情页面更新!换成了正方形的测试点信息,非常帅!
个人博客首页的更新!改变了页面风格,右侧对齐了火焰图,特别帅!
博客详情页的更新!同样,右边加了个人信息,让页面更丰富,贼帅!
dsv4f 太屌了!
中秋假期,我拿伟大的 deepseek harness 接入 dsv4f,随后惊喜地发现了 WyOJ 的两个重大 bug,都与“复制题目”相关。
下面是 dsv4f 撰写的 bug 报告。
3b6cabd4(老布局:仓库根即 web 根)wyoj-security-fixes.patch(22 个文件,已应用到线上)| No | 严重度 | 类型 | 位置 | 状态 |
|---|---|---|---|---|
| 1 | 高 | 未认证 SQL 注入 + 命令注入 + 反射型 XSS | app/controllers/problem_set.php |
已修 |
| 2 | 高 | judger 上报字段 SQL 注入 | app/controllers/judge/submit.php |
已修 |
| 3 | 中 | 存储型 XSS(4 类数据 / 20 处输出) | 多处 | 已修 |
| 4 | 中 | CSRF(赞踩 / 私信 / 切换展示勋章) | 3 个裸 POST | 已修 |
| 5 | 中 | HTML::escape() 不转义单引号 |
app/models/HTML.php:5 |
已修 |
problem_set.php:未认证 SQL 注入 + 命令注入 + 反射型 XSS位置:"复制题目"分支(修复前 :39-64)与"迁移题目"分支(修复前 :16-19)。
影响
- 未登录即可盲注数据库(同一个 $pid 同时流向 SQL 和 shell);
- 有题目控制权的人可让 web 容器执行任意命令(即 web 主机 RCE);
- 附带一处反射型 XSS。
复现(修复前)
1. SQL 注入:POST /problems,copy_problem_submit=submit©_problem_list=0 or sleep(3) → 响应延迟约 3 秒(对照 copy_problem_list=1 不延迟)。原因:queryProblemBrief($pid) 把 $pid 直接插进 select * from problems where id = $pid,而它作为权限判断的参数先被求值,因此在 becomeMsgPage() 终止请求之前就已执行。
命令注入:同一字段填 1; id >/tmp/pwned(需先通过第一轮权限检查,即出题人/超管),$pid 进入 dataCopyProblemData() → exec("cp -r /var/uoj_data/$src …")。
反射型 XSS:POST /problems,migrate_problem_submit=submit&target_group=<script>alert(1)</script>&start_pid=1&end_pid=1 → "未找到组 …" 原样回显。
附带 bug:if (!group) 把 group 当常量(求值为真值字符串 'group'),这个"组不存在"守卫从未生效;PHP 8 下直接 fatal。
根因:外部输入未校验就进入 SQL 与 shell 命令;错误消息未转义。
修复
- problem_set.php:52-61:每个 pid 在使用前 validateUInt()(一处同时堵掉 SQL 注入与命令注入,因为同一变量流向两处);:20 转义 $_POST['target_group'];两个 POST 分支加登录门槛。
- app/libs/uoj-data-lib.php:5-41:data*Problem() 系列改用 escapeshellarg() + dataCheckId()(纵深防御,防未来调用方再引入)。
judge/submit.php:judger 上报字段 SQL 注入位置:app/controllers/judge/submit.php(修复前 :32-38、:63-69、:75-77)。
影响:通过 authenticateJudger()(口令比对 judger_info,而仓库预置的是公开占位符 _judger_password_)后,result JSON 里的 status / error 被直接拼进 SQL,score / time / memory 连引号都没有 → 完整 SQL 注入,可改任意表。$_POST['id'] 本身在派发处有 validateUInt,不是注入点。
复现(修复前,需一个有效 judger 账号):POST /judge/submit,带 submit=1&id=1,把 result 的 status 填成 Judged', score=0 where 1=1 -- 即可改变写入语义。
根因:把不可信 JSON 当作 SQL 字面量拼接。
修复:新增 judgeResultFromPost()(:12)统一解码并拒绝非数组;status/error 走 DB::escape()(:48、:50、:84),score/time/memory/success 强制 (int)(列类型本就是 int(11)/tinyint(1),与 judger 端的 int() 一致)。
| 数据 | 谁能写 | 修复前的输出点 |
|---|---|---|
motto |
任何注册用户 | index.php:699/730/757、uoj-html-lib.php:1240、views/blog-preview.php:37 |
组昵称(存于 user_info.email) |
组管理员 | group_info.php:9,27、user_info.php:16-18、uoj-html-lib.php:432/496、groups_manage.php:87、problem.php:295、problem_set.php:98 |
| 题目标题 / 远端题目标题 | 出题人 | getProblemLink/getContestProblemLink、echoGroupProblemList/SizeList、problem.php:220/230、problem_statistics.php:62、rps.php:11、4 处管理页标题 |
| 勋章显示名 | 组管理员 / 超管 | echoCertsList 的 $text |
复现(修复前):个人设置里把格言设为 <img src=x onerror=alert(1)>(28 字符,validateMotto 只校验长度)→ 打开首页,脚本在所有访客浏览器中执行。组昵称、题目标题同理(写入端分别是"validator 直接 return '';"和"只做 DB::escape")。
根因:输入端只做长度/存在性校验,输出端不转义。
修复:20 处输出统一 HTML::escape()。
注意(易踩):blog 标题不要在输出端转义——它在写入时已被 UOJBlogEditor.php:96 转义,再转一次会双重转义。因此 getBlogLink() 保持原样。这个仓库混用了"存储时转义"和"输出时转义"两种风格。
| 端点 | 后果 | 修复 |
|---|---|---|
click_zan.php |
冒用受害者身份刷赞/踩 | :20 加 crsf_defend();js/uoj.js 带 _token |
user_msg.php |
以受害者名义发私信 | :102 加 crsf_defend();页面 JS 带 _token |
certs_manage.php |
改掉受害者展示的勋章 | :36 加 crsf_defend();表单加 HTML::hiddenToken() |
复现(修复前):在任意第三方页面放置自动提交的表单,指向 https://<host>/click-zan,字段 id=1&delta=1&type=P;受害者登录状态下访问该页即被记账。
根因:UOJForm 生成的表单内部会校验 token(uoj-form-lib.php:49,277),但这三处是手写表单/AJAX,绕过了它。
修复:端点加 crsf_defend();page-header.php 暴露 uojCsrfToken 给 JS,并 bump js/uoj.js?v=。bump 版本号是必须的——否则浏览器缓存的旧 JS 不带 token,赞踩会全部失效。
HTML::escape() 不转义单引号位置:app/models/HTML.php:5(修复前是裸 htmlspecialchars($str),PHP 7.4 默认 ENT_COMPAT)。
影响:user_info.php:24 把 bgurl 放进单引号 CSS 字符串 url('<…>'),而 bgurl 存储时只做 DB::escape(certs_manage.php:53)→ 一个 ' 就能闭合字符串注入 CSS 声明(视觉劫持、借 url() 外带信息;现代浏览器不会执行 JS)。
复现(修复前):设置背景地址为 x');background:url(//attacker/),查看自己主页的 style 属性。
修复:htmlspecialchars($str, ENT_QUOTES, 'UTF-8')。已确认 HTML::escape 的输出没有任何一处落在 <script> 块内,不会破坏 JS。
php -l 全部改动文件(本机无 php,未过 lint)。<img src=x onerror=alert(1)> → 显示字面文本,不弹窗。This page has expired.judge/submit.php 的转义没有破坏协议)。由于 @zxh_qwq 对 Rating 系统提出了疑问,认为他的 Rating 系统更优,我们不妨根据 WyOJ 的历史数据对比一下现有的 Rating 系统(Glicko-2)和他提出的 Perf 等差、向 Perf 移动 $\delta / 5$ 的简单 Rating 系统。 $$ \begin{array}{r|l|r|r|r|r} \text{排名} & \text{用户名} & \text{最终 Rating} & \text{最大回撤} & \text{期望} & \text{方差} \\ \hline 1 & \text{zrl123456} & 2421.10 & 88.69\ (3.77\%) & 2137.73 & 66332.17 \\ 2 & \text{ANDER_} & 2358.09 & 337.53\ (22.50\%) & 1700.67 & 117009.39 \\ 3 & \text{KSCD_} & 2303.37 & 0.00\ (0.00\%) & 1933.70 & 71649.81 \\ 4 & \text{Ame_wiki} & 2273.11 & 223.80\ (12.20\%) & 1903.81 & 70908.29 \\ 5 & \text{aaa} & 2238.02 & 0.00\ (0.00\%) & 1907.84 & 65392.64 \\ 6 & \text{Pigsyy} & 2182.06 & 0.00\ (0.00\%) & 1864.32 & 52585.94 \\ 7 & \text{lzx} & 2152.91 & 119.12\ (5.47\%) & 1920.19 & 56075.78 \\ 8 & \text{wfandy} & 2074.79 & 0.00\ (0.00\%) & 1789.83 & 44398.23 \\ 9 & \text{taccat} & 2061.42 & 307.53\ (14.83\%) & 1828.49 & 25156.47 \\ 10 & \text{wyz} & 2057.55 & 182.63\ (8.23\%) & 1825.61 & 48767.76 \\ 11 & \text{FiraCode} & 1971.40 & 117.74\ (7.85\%) & 1636.94 & 46000.45 \\ 12 & \text{Gejunyi} & 1968.54 & 389.44\ (20.33\%) & 1696.09 & 33460.92 \\ 13 & \text{zxh_qwq} & 1922.19 & 390.29\ (20.43\%) & 1734.50 & 98465.76 \\ 14 & \text{xyh13793601192} & 1907.44 & 0.00\ (0.00\%) & 1716.32 & 21605.07 \\ 15 & \text{_awa_wangjiawen}& 1902.52 & 341.02\ (19.45\%) & 1593.94 & 24096.83 \\ 16 & \text{Dtw} & 1879.18 & 78.66\ (5.10\%) & 1739.44 & 32269.68 \\ 17 & \text{rengpuiyang} & 1866.76 & 238.59\ (13.97\%) & 1619.42 & 18557.34 \\ 18 & \text{Little_Cck} & 1839.22 & 347.64\ (22.85\%) & 1448.36 & 24480.07 \\ 19 & \text{zibenlun} & 1837.13 & 104.57\ (6.97\%) & 1578.87 & 21080.86 \\ 20 & \text{tths01y} & 1796.99 & 43.14\ (2.61\%) & 1639.27 & 11342.89 \\ \end{array} $$
注意到,ANDER_ 超了 KSCD_ 和 aaa,Ame_wiki 超了 aaa。其余的各种问题,我没有心情细细观察。
我们可以非常简单、快速、轻松、自在极意地发现这个 Rating 系统存在许多缺点:
首先,他完全不考虑你对手是谁。只要你打了第一,Perf 就是 max_rating。只要你打了倒数第一,Perf 就是 min_rating。如果为了简单性,直接把对手是谁忘了,那你算的那还叫 Rating 吗。
况且,由于 Perf 的范围固定,导致不可能存在长期的上涨,所有人的 Rating 都趋于同一个范围。这就导致越高水平的人,虽然他理论上应该有更高的 Rating,但因为算法缺陷,他的 Rating 却始终被往下拉。
此外,这个 Rating 系统完全没有波动率,也就是 Glicko-2 中的 Vol,这就导致无法判断某个人最近的状态。Glicko-2 的极大好处之一就是,你可以快速地判断一个人最近是稳定发挥还是爆冷。
其次,水平相近的选手之间波动相当大。两个 Rating 接近、排名相邻的参赛选手,按他的算法,有一个巨大的 Perf 差。这会造成他们两个都长时间上不了分,尽管他们比排名靠后的选手厉害。
@zxh_qwq 指出,“比赛数很少,用大型算法‘不够优秀’,不如用这个。”我想知道,以在比赛少的情况下发挥显著好于常见的 Rating 系统而著称的 Glicko-2,咋就突然不够优秀了呢?况且这个算法有什么证据说明他对比赛少的情况友好?
@zxh_qwq 指出,“太复杂了不好”,这句话实现了时空穿越!因为 Glicko-2 显然完全优于以上这个 Rating 算法,而所谓的“复杂”只存在于我实现这一算法之前。既然我已经实现了这一能够完全偏序他提出的 Rating 算法的优越算法,还存在什么“复杂”可言呢?看来,时空穿越对他来说已经完全不是问题了。
@zxh_qwq 指出,“别再折腾了,就这样吧”。读完这句话,我仿佛陷入了梦境,身边的一切都飘渺起来,因为这句话让我陷入了一种震撼的境地:折腾的人,难道不是我吗?我耗费了好几天的时间,研究了各种 Rating 系统,最后选择并用了一中午实现了 Glicko-2,这些“折腾”,居然可以用一段语法都不正确的代码搪塞过去,“就这样吧”,吾今羽化而登仙矣!
三列分别是:比赛 ID,用户名,排名。
"1","alt","1"
"1","ryp","2"
"3","lgvc","1"
"3","cxm1024","2"
"3","jxy2012","3"
"3","recall","4"
"3","xxxbt","5"
"3","Un1quAIoid","6"
"3","Dtw","7"
"3","lzx","8"
"3","zibenlun","9"
"3","zxh_qwq","10"
"3","handezheng","10"
"3","contest","10"
"3","star_field","10"
"3","lsxhyyds","10"
"3","danio1029","10"
"3","xuyunao","10"
"4","alt","1"
"5","lzx","1"
"5","taccat","2"
"5","quyuan","3"
"5","xuyunao","4"
"5","_awa_wangjiawen","5"
"5","Ame_wiki","6"
"5","FXLIR","7"
"5","zhangyining2357","8"
"5","wyz","9"
"5","protractor","10"
"5","WZL1212","11"
"5","Jtwang1","12"
"5","wukuncheng","13"
"5","gctiruct","14"
"5","S08577","15"
"5","Base_ring_tree","16"
"5","wfirstzhang","17"
"5","dongyiyang","18"
"5","tanzicheng","19"
"5","zxh_qwq","20"
"5","lihaobei","21"
"5","yzs","22"
"5","handezheng","23"
"5","zrq2010","24"
"6","lzx","1"
"6","_awa_wangjiawen","2"
"6","gctiruct","3"
"6","zxh_qwq","4"
"6","handezheng","5"
"6","protractor","6"
"6","yzs","7"
"6","FiraCode","8"
"6","xuyunao","9"
"6","tianruihan","10"
"7","rengpuiyang","1"
"7","aaa","2"
"7","KSCD_","3"
"7","gctiruct","4"
"7","Pigsyy","5"
"7","lzx","6"
"7","xuyunao","7"
"7","FiraCode","8"
"7","protractor","9"
"7","quyuan","10"
"7","S08577","11"
"7","cybrex","12"
"7","Dtw","13"
"7","zibenlun","14"
"7","handezheng","15"
"7","tianruihan","16"
"7","YangShangLin","16"
"7","LiuYiPing","16"
"7","ZhouKangYang","16"
"8","zrl123456","1"
"8","zxh_qwq","2"
"8","lihaobei","3"
"8","wfirstzhang","4"
"8","yuanjingxuan","5"
"8","dongyiyang","6"
"8","FXLIR","7"
"8","Jtwang1","8"
"8","keep_shining","9"
"8","liwenhan","10"
"8","WF_wxl","11"
"8","star_field","12"
"8","SaintRelief","13"
"8","xhl_leo","14"
"8","Little_Cck","15"
"8","Base_ring_tree","16"
"8","Gejunyi","17"
"8","taccat","18"
"8","hatred","19"
"8","yzs","20"
"8","ANDER_","21"
"8","hai_kerr","22"
"8","ruiqi2012","23"
"8","Lin_Yi_Rui","24"
"8","wyz","25"
"8","thr_31825","26"
"8","ljm","27"
"8","why110623","28"
"8","woden","29"
"8","_awa_wangjiawen","29"
"8","YangShangLin","29"
"8","LiuYiPing","29"
"8","ZhouKangYang","29"
"10","zrl123456","1"
"10","lzx","2"
"10","KSCD_","3"
"10","Pigsyy","4"
"10","protractor","5"
"10","handezheng","6"
"10","Dtw","7"
"10","zibenlun","8"
"10","quyuan","9"
"10","S08577","10"
"10","cybrex","11"
"10","wyz","12"
"10","xuyunao","13"
"10","tianruihan","14"
"10","taccat","15"
"10","dongyiyang","16"
"10","Jtwang1","17"
"10","star_field","18"
"10","ruiqi2012","19"
"10","wfirstzhang","20"
"10","WF_wxl","21"
"10","lihaobei","22"
"10","Lin_Yi_Rui","23"
"10","yzs","24"
"10","Base_ring_tree","25"
"10","FiraCode","26"
"10","yuanjingxuan","27"
"10","hatred","28"
"10","_awa_wangjiawen","29"
"10","FXLIR","30"
"10","thr_31825","31"
"10","Little_Cck","32"
"10","liwenhan","33"
"10","xhl_leo","34"
"10","qcd_fisher","35"
"10","keep_shining","36"
"10","why110623","37"
"10","ljm","38"
"10","Joe20110905","39"
"10","zhangyining2357","40"
"10","woden","41"
"10","SaintRelief","42"
"10","ANDER_","43"
"10","zhang2010","44"
"10","zxh_qwq","45"
"10","Gejunyi","46"
"10","rengpuiyang","47"
"10","ygbyt","48"
"10","lsxhyyds","48"
"11","aaa","1"
"11","Pigsyy","2"
"11","KSCD_","3"
"11","rengpuiyang","4"
"11","zrl123456","5"
"11","lzx","6"
"11","gctiruct","7"
"11","FiraCode","8"
"11","quyuan","9"
"11","handezheng","10"
"11","Dtw","11"
"11","zibenlun","12"
"11","cybrex","13"
"11","S08577","14"
"11","taccat","15"
"11","Gejunyi","16"
"11","haiker","17"
"11","Jtwang1","18"
"11","lihaobei","19"
"11","star_field","20"
"11","tianruihan","21"
"11","xuyunao","22"
"11","ANDER_","23"
"11","Little_Cck","24"
"11","woden","25"
"11","keep_shining","26"
"11","zhangyining2357","27"
"11","WF_wxl","28"
"11","lijunda","29"
"11","zxh_qwq","30"
"11","dongyiyang","31"
"11","wyz","32"
"11","_awa_wangjiawen","33"
"11","FXLIR","34"
"11","Ame_wiki","35"
"11","SaintRelief","36"
"11","xhl_leo","37"
"11","liwenhan","38"
"11","hatred","39"
"11","ruiqi2012","40"
"11","yzs","41"
"11","OPEC","42"
"11","protractor","43"
"11","Base_ring_tree","44"
"11","why110623","45"
"11","zhang2010","46"
"11","wfirstzhang","47"
"11","yuanjingxuan","48"
"11","CZM","49"
"11","thr_31825","50"
"11","ljm","51"
"11","zyq777","52"
"11","Joe20110905","52"
"12","asd","1"
"14","aaa","1"
"14","KSCD_","2"
"14","lzx","3"
"14","FiraCode","4"
"14","zibenlun","5"
"14","Dtw","6"
"14","Ame_wiki","7"
"14","lihaobei","8"
"14","zxh_qwq","9"
"14","zrl123456","10"
"14","Gejunyi","11"
"14","cybrex","12"
"14","gctiruct","13"
"14","quyuan","14"
"14","S08577","15"
"14","tianruihan","16"
"14","Pigsyy","17"
"14","handezheng","18"
"14","wyz","19"
"14","hatred","20"
"14","keep_shining","21"
"14","_awa_wangjiawen","22"
"14","star_field","23"
"14","SaintRelief","24"
"14","Jtwang1","25"
"14","dongyiyang","26"
"14","why110623","27"
"14","ljm","28"
"14","ruiqi2012","29"
"14","xuyunao","30"
"14","yuanjingxuan","31"
"14","Little_Cck","32"
"14","xhl_leo","33"
"14","OPEC","34"
"14","wukuncheng","35"
"14","liwenhan","36"
"14","zhangyining2357","37"
"14","yzs","38"
"14","lijunda","39"
"14","Lin_Yi_Rui","40"
"14","rengpuiyang","41"
"14","taccat","42"
"14","woden","43"
"14","thr_31825","44"
"14","WF_wxl","45"
"14","haiyixuan","46"
"14","ANDER_","47"
"14","FXLIR","48"
"14","Base_ring_tree","49"
"14","CZM","50"
"14","zibunlen","51"
"14","wfirstzhang","51"
"15","Pigsyy","1"
"15","aaa","2"
"15","zrl123456","3"
"15","FiraCode","4"
"15","Dtw","5"
"15","xuyunao","6"
"15","Gejunyi","7"
"15","handezheng","8"
"15","gctiruct","9"
"15","yzs","10"
"15","lzx","11"
"15","tianruihan","12"
"15","rengpuiyang","13"
"15","zxh_qwq","14"
"15","_awa_wangjiawen","15"
"15","cybrex","16"
"15","ANDER_","17"
"15","protractor","18"
"15","quyuan","19"
"16","rengpuiyang","1"
"16","KSCD_","2"
"16","lzx","3"
"16","zrl123456","4"
"16","zxh_qwq","5"
"16","FiraCode","6"
"16","handezheng","7"
"16","gctiruct","8"
"16","xuyunao","9"
"16","_awa_wangjiawen","10"
"16","Dtw","11"
"16","wyz","12"
"16","cybrex","13"
"16","S08577","14"
"16","protractor","15"
"16","quyuan","16"
"16","tianruihan","17"
"16","__vector__","18"
"16","Quantum","19"
"16","yzs","19"
"16","WF_wxl","19"
"17","zrl123456","1"
"17","taccat","2"
"17","_awa_wangjiawen","3"
"17","wyz","4"
"17","Gejunyi","5"
"17","protractor","6"
"17","ANDER_","7"
"17","star_field","8"
"17","quyuan","9"
"17","keep_shining","10"
"17","Little_Cck","11"
"17","lihaobei","12"
"17","wfirstzhang","13"
"17","tianruihan","14"
"17","WF_wxl","15"
"17","yzs","16"
"17","wangchen101","17"
"17","zxh_qwq","18"
"17","Quantum","19"
"17","cybrex","20"
"18","zrl123456","1"
"18","Gejunyi","2"
"18","ruiqi2012","3"
"18","quyuan","4"
"18","zxh_qwq","5"
"18","S08577","6"
"18","yzs","7"
"18","wyz","8"
"18","taccat","9"
"18","Jtwang1","10"
"18","_awa_wangjiawen","11"
"18","WF_wxl","12"
"18","star_field","13"
"18","keep_shining","14"
"18","wfirstzhang","15"
"18","tianruihan","16"
"18","Little_Cck","17"
"18","ANDER_","18"
"18","liwenhan","19"
"18","xhl_leo","20"
"18","woden","21"
"18","wangchen101","22"
"18","Quantum","23"
"18","protractor","23"
"18","fuyixiang","23"
"18","lihaobei","23"
"18","zhangzexi","23"
"19","KSCD_","1"
"19","aaa","2"
"19","Pigsyy","3"
"19","rengpuiyang","4"
"19","zrl123456","5"
"19","lzx","6"
"19","handezheng","7"
"19","Dtw","8"
"19","quyuan","8"
"19","cybrex","8"
"19","gctiruct","8"
"19","Little_Cck","8"
"19","Quantum","8"
"19","Jtwang1","8"
"19","WF_wxl","8"
"19","star_field","8"
"19","protractor","8"
"19","xhl_leo","8"
"19","__vector__","8"
"20","wfirstzhang","1"
"20","Ame_wiki","2"
"20","taccat","3"
"20","ANDER_","4"
"20","wyz","5"
"20","keep_shining","6"
"20","ruiqi2012","7"
"20","Jtwang1","8"
"20","Little_Cck","9"
"20","star_field","10"
"20","wangchen101","11"
"20","wwwzzzlll","12"
"20","xhl_leo","13"
"20","CZMM","14"
"20","WF_wxl","15"
"20","fuyixiang","16"
"20","___W___Z___L___PVP","17"
"20","OPEC","18"
"20","woden","19"
"20","liwenhan","19"
"22","_awa_wangjiawen","1"
"22","Jtwang1","2"
"22","star_field","3"
"22","wyz","4"
"22","liwenhan","5"
"22","fuyixiang","6"
"22","wangchen101","7"
"22","WF_wxl","8"
"22","quyuan","9"
"22","ANDER_","10"
"22","ruiqi2012","11"
"22","Little_Cck","12"
"22","wfirstzhang","13"
"22","keep_shining","14"
"22","taccat","15"
"22","woden","16"
"22","yzs","17"
"23","protractor","1"
"23","taccat","2"
"23","zxh_qwq","3"
"23","ANDER_","4"
"23","quyuan","5"
"23","wangchen101","6"
"23","ruiqi2012","7"
"23","OPEC","8"
"23","liwenhan","9"
"23","xhl_leo","10"
"23","S08577","11"
"23","tianruihan","12"
"23","xuyunao","13"
"23","wfirstzhang","14"
"23","Jtwang1","15"
"23","fuyixiang","16"
"23","wyz","17"
"23","woden","18"
"23","Quantum","19"
"23","WF_wxl","20"
"23","Little_Cck","21"
"23","cybrex","22"
"23","Ame_wiki","23"
"23","keep_shining","23"
"23","yzs","23"
"23","Base_ring_tree","23"
"23","handezheng","23"
"24","YangShangLin","1"
"25","wyz","1"
"25","yzs","2"
"25","zxh_qwq","3"
"25","Jtwang1","4"
"25","_awa_wangjiawen","5"
"25","taccat","6"
"25","Quantum","7"
"25","handezheng","8"
"25","Dtw","9"
"25","woden","10"
"25","protractor","11"
"25","cybrex","12"
"25","fuyixiang","13"
"25","ruiqi2012","14"
"25","OPEC","15"
"25","WF_wxl","16"
"25","wangchen101","17"
"25","Little_Cck","17"
"25","ANDER_","17"
"25","quyuan","17"
"25","keep_shining","17"
"25","tianruihan","17"
"25","INnoVation__","17"
"27","wfyz57","1"
"27","wfyz32","2"
"27","wfyz154","3"
"27","wfyz38","4"
"27","wfyz34","5"
"27","wfyz6","6"
"27","wfyz21","7"
"27","wfyz33","8"
"27","wfyz46","9"
"27","wfyz58","10"
"27","wfyz45","11"
"27","zibunlen","12"
"27","wfyz140","13"
"27","wfyz28","14"
"27","wfyz64","15"
"27","wfyz60","16"
"27","wfyz65","17"
"27","wfyz41","18"
"27","wfyz37","19"
"27","wfyz44","20"
"27","wfyz113","21"
"27","wfyz79","22"
"27","wfyz84","23"
"27","wfyz51","24"
"27","wfyz43","25"
"27","wfyz13","26"
"27","wfyz77","27"
"27","wfyz16","28"
"27","wfyz54","29"
"27","wfyz97","30"
"27","wfyz42","31"
"27","wfyz103","32"
"27","wfyz94","33"
"27","wfyz87","34"
"27","wfyz68","35"
"27","wfyz86","36"
"27","wfyz55","37"
"27","wfyz151","38"
"27","wfyz69","39"
"27","wfyz76","40"
"27","wfyz128","41"
"27","wfyz85","42"
"27","wfyz4","43"
"27","wfyz106","44"
"27","wfyz62","45"
"27","wfyz150","46"
"27","wfyz75","47"
"27","wfyz117","48"
"27","wfyz100","49"
"27","wfyz1","50"
"27","wfyz24","51"
"27","wfyz66","52"
"27","wfyz27","53"
"27","wfyz162","54"
"27","wfyz25","55"
"27","wfyz47","56"
"27","wfyz26","57"
"27","wfyz96","58"
"27","wfyz136","59"
"27","wfyz30","60"
"27","wfyz40","61"
"27","wfyz7","62"
"27","wfyz166","63"
"27","wfyz50","64"
"27","wfyz131","65"
"27","wfyz116","66"
"27","wfyz3","67"
"27","wfyz155","68"
"27","wfyz104","69"
"27","wfyz49","70"
"27","wfyz112","71"
"27","wfyz125","72"
"27","wfyz121","73"
"27","wfyz105","74"
"27","wfyz119","75"
"27","wfyz132","76"
"27","wfyz63","77"
"27","wfyz91","78"
"27","wfyz70","79"
"27","wfyz167","80"
"27","wfyz80","81"
"27","wfyz92","82"
"27","wfyz61","83"
"27","wfyz22","84"
"27","wfyz18","85"
"27","wfyz138","86"
"27","wfyz81","87"
"27","wfyz110","88"
"27","wfyz53","89"
"27","wfyz109","90"
"27","wfyz118","91"
"27","wfyz144","92"
"27","wfyz135","93"
"27","wfyz39","94"
"27","wfyz5","95"
"27","wfyz93","96"
"27","wfyz139","97"
"27","wfyz11","98"
"27","wfyz108","99"
"27","wfyz78","100"
"27","wfyz89","101"
"27","wfyz2","102"
"27","wfyz161","103"
"27","wfyz141","104"
"27","wfyz19","105"
"27","wfyz129","106"
"27","wfyz160","107"
"27","wfyz17","108"
"27","wfyz157","109"
"27","wfyz111","110"
"27","wfyz133","111"
"27","wfyz168","112"
"27","wfyz74","113"
"27","wfyz82","114"
"27","wfyz143","115"
"27","wfyz107","116"
"27","wfyz145","117"
"27","wfyz142","118"
"27","wfyz130","119"
"27","wfyz146","120"
"27","wfyz126","121"
"27","wfyz123","122"
"27","wfyz90","123"
"27","wfyz98","124"
"27","wfyz102","125"
"27","wfyz120","126"
"27","wfyz67","127"
"27","wfyz35","128"
"27","wfyz153","129"
"27","wfyz83","130"
"27","wfyz114","131"
"27","wfyz122","132"
"27","wfyz95","133"
"27","wfyz156","134"
"27","wfyz59","135"
"27","wfyz124","136"
"27","wfyz72","137"
"27","wfyz48","138"
"27","wfyz115","139"
"27","wfyz31","140"
"27","wfyz127","141"
"27","wfyz149","142"
"27","wfyz164","143"
"27","wfyz73","144"
"27","wfyz134","145"
"27","wfyz159","146"
"27","wfyz8","147"
"27","wfyz148","148"
"27","wfyz29","149"
"27","wfyz99","150"
"27","wfyz137","151"
"27","wfyz101","152"
"27","wfyz152","153"
"27","wfyz71","154"
"27","wfyz147","155"
"27","wfyz165","156"
"27","wfyz52","156"
"27","wfyz158","156"
"27","wfyz88","156"
"27","wfyz163","156"
"27","YangShangLin","156"
"28","alt","1"
"28","Anonymous","2"
"29","Anonymous","1"
"29","zibunlen","2"
"30","Jtwang1","1"
"30","ANDER_","2"
"30","Little_Cck","3"
"30","Gejunyi","4"
"30","fuyixiang","5"
"30","quyuan","6"
"30","ruiqi2012","7"
"30","woden","8"
"30","Lin_Yi_Rui","9"
"30","WF_wxl","10"
"30","wangchen101","11"
"30","wfirstzhang","12"
"30","OPEC","13"
"31","wyz","1"
"31","taccat","2"
"31","wfirstzhang","3"
"31","WF_wxl","4"
"31","wangchen101","5"
"31","Jtwang1","6"
"31","ANDER_","7"
"31","fuyixiang","8"
"31","Little_Cck","9"
"31","zxh_qwq","10"
"31","star_field","11"
"31","Lin_Yi_Rui","12"
"31","yuanjingxuan","13"
"31","lijunda","13"
"31","Ame_wiki","13"
"32","zxh_qwq","1"
"32","ANDER_","2"
"32","taccat","3"
"32","Ame_wiki","4"
"32","wyz","5"
"32","ruiqi2012","6"
"32","quyuan","7"
"32","wfirstzhang","8"
"32","star_field","9"
"32","Little_Cck","10"
"32","woden","11"
"32","WF_wxl","12"
"32","Gejunyi","13"
"32","Jtwang1","14"
"32","Lin_Yi_Rui","15"
"32","xhl_leo","16"
"32","lihaobei","17"
"32","wangchen101","18"
"32","cybrex","18"
"33","zxh_qwq","1"
"33","alt","2"
"33","taccat","3"
"33","wyz","4"
"33","ANDER_","5"
"33","quyuan","6"
"33","FXLIR","7"
"33","___W___Z___L___PVP","8"
"33","WZP","9"
"33","lxc123456","10"
"33","Gejunyi","11"
"33","Jtwang1","12"
"33","Base_ring_tree","13"
"33","WF_wxl","14"
"33","zhaozihan_123456","15"
"33","lihaobei","16"
"33","liwenhan","17"
"33","wangchen101","18"
"33","zhangyining2357","19"
"33","star_field","20"
"33","Lin_Yi_Rui","21"
"33","ruiqi2012","22"
"33","woden","23"
"33","fuyixiang","23"
"33","cybrex","23"
"34","FXLIR","1"
"34","lhj","2"
"34","gaoyunhan","3"
"34","red_wood","4"
"34","ojzbh0011","5"
"34","wfandy","6"
"34","lihaoze2012","7"
"34","zhaozihan_123456","8"
"34","mingjun666","9"
"34","xyx0011","10"
"34","lichengze","11"
"34","liuyian","12"
"34","WEZ","13"
"34","mengjh","14"
"34","songyitong","15"
"34","zhangchao123","16"
"34","FuShulong","17"
"34","hsliujunxi","18"
"34","lyw08128","19"
"34","kyx","20"
"34","XWD_YS","21"
"34","FengQiYunYong","22"
"34","WF_wxl","23"
"34","fuyixiang","23"
"34","Little_Cck","23"
"35","Ame_wiki","1"
"35","zrl123456","2"
"35","ruiqi2012","3"
"35","zxh_qwq","4"
"35","ANDER_","5"
"35","woden","6"
"35","wyz","7"
"35","wfirstzhang","8"
"35","taccat","9"
"35","quyuan","10"
"35","Little_Cck","11"
"35","Gejunyi","12"
"35","fuyixiang","13"
"35","Jtwang1","14"
"35","Lin_Yi_Rui","15"
"35","WF_wxl","16"
"35","star_field","17"
"36","FiraCode","1"
"36","octopus_eats_cat","2"
"36","star_field","3"
"36","Gejunyi","4"
"36","quyuan","5"
"36","Ame_wiki","5"
"36","wyz","5"
"36","WF_wxl","5"
"36","Little_Cck","5"
"36","woden","5"
"36","ruiqi2012","5"
"36","Jtwang1","5"
"36","fuyixiang","5"
"36","ANDER_","5"
"36","Lin_Yi_Rui","5"
"36","zxh_qwq","5"
"36","zrl123456","5"
"38","taccat","1"
"38","Ame_wiki","2"
"38","Jtwang1","3"
"38","Little_Cck","4"
"38","zrl123456","5"
"38","quyuan","6"
"38","S08577","7"
"38","woden","8"
"38","WF_wxl","9"
"38","ruiqi2012","10"
"38","fuyixiang","11"
"38","ANDER_","12"
"38","Lin_Yi_Rui","13"
"39","zrl123456","1"
"39","Gejunyi","2"
"39","Ame_wiki","3"
"39","quyuan","4"
"39","Jtwang1","5"
"39","WF_wxl","6"
"39","ruiqi2012","7"
"39","ANDER_","8"
"39","woden","9"
"39","Lin_Yi_Rui","10"
"39","Little_Cck","11"
"39","S08577","12"
"39","fuyixiang","13"
"39","taccat","14"
"39","wfirstzhang","15"
"40","zrl123456","1"
"40","wfirstzhang","2"
"40","quyuan","3"
"40","taccat","4"
"40","Lin_Yi_Rui","5"
"40","fuyixiang","6"
"40","Little_Cck","7"
"40","ruiqi2012","8"
"41","ANDER_","1"
"41","WF_wxl","2"
"41","Lin_Yi_Rui","3"
"41","wfirstzhang","4"
"41","fuyixiang","5"
"41","ruiqi2012","6"
"41","woden","7"
"41","Jtwang1","8"
"41","Little_Cck","9"
"41","quyuan","10"
"41","Gejunyi","11"
"42","zrl123456","1"
"42","zxh_qwq","2"
"42","Ame_wiki","3"
"42","wyz","4"
"42","Little_Cck","5"
"42","Gejunyi","6"
"42","taccat","7"
"42","ANDER_","8"
"42","ruiqi2012","9"
"42","quyuan","10"
"42","Jtwang1","11"
"42","S08577","12"
"42","woden","13"
"42","wfirstzhang","14"
"42","WF_wxl","15"
"42","fuyixiang","16"
"43","xyh13793601192","1"
"43","tths01y","2"
"43","liuruixvan","3"
"43","weiyubo","4"
"43","cybrex","5"
"43","userdbx","6"
"43","yile2014","7"
"43","abcd123456","8"
"43","lbz___","9"
"43","jfy2015","10"
"43","xiaorui13","11"
"44","wfandy","1"
"44","lbz___","2"
"44","weiyubo","3"
"44","xyh13793601192","4"
"44","Zhr_002033","5"
"44","userdbx","6"
"44","liuruixvan","7"
"44","tths01y","8"
"44","jinkuner","9"
"44","yile2014","10"
"44","abcd123456","11"
"44","python2","12"
"44","jfy2015","13"
"44","lvfufu","14"
"45","Ame_wiki","1"
"45","ANDER_","2"
"45","quyuan","3"
"45","ruiqi2012","4"
"45","Jtwang1","5"
"45","woden","6"
"45","Gejunyi","7"
"45","zxh_qwq","8"
"45","wyz","9"
"45","Lin_Yi_Rui","10"
"45","wfirstzhang","11"
"45","Base_ring_tree","12"
"45","lihaobei","13"
"46","zxh_qwq","1"
"46","ANDER_","2"
"46","wfirstzhang","3"
"46","Gejunyi","4"
"46","taccat","5"
"46","Little_Cck","6"
"46","Jtwang1","7"
"46","wyz","8"
"46","woden","9"
"46","ruiqi2012","10"
"46","star_field","11"
"46","fuyixiang","12"
"46","___W___Z___L___PVP","13"
"46","lvxinyu001","14"
"46","Fisher_OvO","15"
"46","rain_x3","16"
"46","lxc123456","17"
"46","hatred","18"
"46","FXLIR","19"
"46","lihaobei","20"
"46","Lin_Yi_Rui","21"
"46","Alan5","22"
"46","WF_wxl","23"
"46","liwenhan","24"
"46","Base_ring_tree","25"
"46","xvyingxiao","26"
"47","wfandy","1"
"47","Zhr_002033","2"
"47","ojzbh0011","3"
"47","mengjh","4"
"47","zm0402","5"
"47","God_nodog_lhj","6"
"47","lihaoze2012","7"
"47","lvfufu","8"
"47","lichengze","9"
"47","gaoyunhan","10"
"47","ABCDEFG","11"
"47","wenhualjx","12"
"47","zhangchao","13"
"47","WEZ12345","14"
"47","JohnSmith","15"
"48","wyz","1"
"48","ANDER_","2"
"48","Gejunyi","3"
"48","wfirstzhang","4"
"48","zxh_qwq","5"
"48","woden","6"
"48","Jtwang1","7"
"48","Ame_wiki","8"
"48","xhl_leo","9"
"48","FXLIR","10"
"48","WF_wxl","11"
"48","tanzicheng","12"
"48","ruiqi2012","13"
"48","Lin_Yi_Rui","14"
"48","quyuan","15"
"48","___W___Z___L___PVP","16"
"48","Little_Cck","17"
"48","taccat","18"
"48","lihaobei","19"
"48","xvyingxiao","20"
"48","shuxuelianxice","21"
"48","Base_ring_tree","22"
"48","keep_shining","23"
"48","zhangyining2357","24"
"48","rain_x3","25"
"48","zhaozihan_123456","26"
"48","hatred","27"
"48","hai_ker","28"
"48","lxc123456","29"
"48","lvxinyu001","30"
"48","liuxiaolei","31"
"48","zyq777","32"
"48","fuyixiang","33"
"49","wyz","1"
"49","ANDER_","2"
"49","Gejunyi","3"
"49","taccat","4"
"49","Ame_wiki","5"
"49","woden","6"
"49","Little_Cck","7"
"49","Jtwang1","8"
"49","ruiqi2012","9"
"49","WF_wxl","10"
"49","keep_shining","11"
"49","wfirstzhang","12"
"49","fuyixiang","13"
"49","shuxuelianxice","14"
"49","Lin_Yi_Rui","15"
"49","xhl_leo","16"
"49","lihaobei","17"
"49","quyuan","18"
"49","zxh_qwq","19"
"50","tths01y","1"
"50","xyh13793601192","2"
"50","yile2014","3"
"50","Chansonnier","4"
"50","lbz___","5"
"50","jinkuner","6"
"50","python2","7"
"50","userdbx","8"
"50","majingyi","9"
"50","henaiyi","10"
"50","MLK_NS","11"
"50","xyx0011","12"
"50","jfy2015","13"
"50","yulinjiang","14"
"50","luyunqing123","15"
"50","WXY","16"
"50","Zsz141208","17"
"50","mushuaiyu","18"
"50","lirunyang","19"
"50","chenjia2013","20"
"50","xiaorui13","21"
"50","zmy6658","22"
"50","lujiadashao","23"
"50","dongxiawen","24"
"50","fyc_6","25"
"50","trues","26"
"50","kunqi2014","27"
"50","WXQyxl88","28"
"51","taccat","1"
"51","wyz","2"
"51","star_field","3"
"51","ANDER_","4"
"51","Jtwang1","5"
"51","Little_Cck","6"
"51","zxh_qwq","7"
"51","FXLIR","8"
"51","woden","9"
"51","___W___Z___L___PVP","10"
"51","Base_ring_tree","11"
"51","tanzicheng","12"
"51","rain_x3","13"
"51","lvxinyu001","14"
"51","WF_wxl","15"
"51","hatred","16"
"51","lihaobei","17"
"51","wfirstzhang","18"
"51","fuyixiang","19"
"51","xhl_leo","20"
"51","ruiqi2012","21"
"51","Lin_Yi_Rui","22"
"51","quyuan","23"
"52","wfandy","1"
"52","zyq777","2"
"52","zhaozihan_123456","3"
"52","qcd_fisher","4"
"52","zangjh666","5"
"52","Alan5","6"
"52","Zhr_002033","7"
"52","lvfufu","8"
"52","JohnSmith","9"
"52","mengjh","10"
"52","God_nodog_lhj","11"
"52","ojzbh0011","12"
"52","zm0402","13"
"52","lichengze","14"
"52","mingjun123","15"
"52","ABCDEFG","16"
"52","gaoyunhan","17"
"52","whljx_666","18"
"52","songyitong123","19"
"52","WEZ11111","20"
"53","quyuan","1"
"53","wfirstzhang","1"
"53","ANDER_","1"
"53","ruiqi2012","1"
"53","WF_wxl","1"
"53","___W___Z___L___PVP","1"
"53","Jtwang1","1"
"53","taccat","1"
"53","wyz","1"
"53","rain_x3","1"
"53","Base_ring_tree","1"
"53","hai_ker","1"
"53","Fisher_OvO","1"
"54","taccat","1"
"54","ANDER_","2"
"54","quyuan","3"
"54","Little_Cck","4"
"54","woden","5"
"54","Jtwang1","6"
"54","ruiqi2012","7"
"54","zxh_qwq","8"
"54","WF_wxl","9"
"54","wyz","10"
"54","wfirstzhang","11"
"54","Lin_Yi_Rui","12"
"54","star_field","13"
"54","fuyixiang","14"
"54","lihaobei","15"
"55","ANDER_","1"
"55","Ame_wiki","2"
"55","star_field","3"
"55","zxh_qwq","4"
"55","wyz","5"
"55","Little_Cck","6"
"55","Gejunyi","7"
"55","taccat","8"
"55","Lin_Yi_Rui","9"
"55","woden","10"
"55","fuyixiang","11"
"55","WF_wxl","12"
"55","Jtwang1","13"
"55","lihaobei","14"
"55","wfirstzhang","15"
"55","lyw08128","16"
"56","YangShangLin","1"
"56","2yp","2"
Introduction to Mathematical Statistics
Forecasting: Principles and Practice
如题,我们更新到了更先进的 Glicko-2 Rating 系统!
目测现在大家的 Rating 都很合理。
同时,Glicko-2 给我们带来了除了 Rating 外的两个参数:RD 和 Vol。
RD 可以理解为方差,一个人的 Perf 有 95% 的可能在 [Rating - 2RD, Rating + 2RD] 内。
Vol 表示这个人最近表现的波动程度。Vol 大的人,最近表现的特别好,或者特别烂。
我们还添加了一个 Rating 分布图像,在每个人的首页,Rating 曲线下面可以看到。非常有趣。
另外,格言已经回滚。但由于备份文件损坏,回滚到的是 7 月 4 日下午 14:00 的版本。
论文地址:Glicko-2 PDF
代码:
function g2_g($x) {
return 1 / sqrt(1 + 3 * $x * $x / M_PI / M_PI);
}
function g2_E($u, $uj, $pj) {
return 1 / (1 + exp(-g2_g($pj) * ($u - $uj)));
}
function g2_f($x, $delta, $phi, $v, $a, $tau) {
return (exp($x) * ($delta * $delta - $phi * $phi - $v - exp($x))
/ (2 * pow($phi * $phi + $v + exp($x), 2)))
- ($x - $a) / $tau / $tau;
}
function calcRatingGlicko2($standings, &$new_rating, &$new_rd, &$new_vol) {
$TAU = 0.6;
$n = count($standings);
$rating = array();
$rd = array();
$vol = array();
for ($i = 0; $i < $n; ++$i) {
$rating[$i] = ($standings[$i][2][1] - 1500) / 173.7178;
$rd[$i] = $standings[$i][2][2] / 173.7178;
$vol[$i] = ($standings[$i][2][3] ?? 0.06);
if ($vol[$i] <= 0) $vol[$i] = 0.06;
}
if ($n == 1) {
$new_rating[0] = $rating[0];
$new_rd[0] = $rd[0];
$new_vol[0] = $vol[0];
}
for ($i = 0; $i < $n; $i++) {
$delta = 0;
$v = 0;
for ($j = 0; $j < $n; $j++) if ($i != $j) {
$s = 0;
if ($standings[$i][3] > $standings[$j][3])
$s = 0;
else if ($standings[$i][3] == $standings[$j][3])
$s = 0.5;
else
$s = 1;
$e = g2_E($rating[$i], $rating[$j], $rd[$j]);
$v += pow(g2_g($rd[$j]), 2) * $e * (1 - $e);
$delta += g2_g($rd[$j]) * ($s - $e);
}
if ($v < 1e-20) $v = 1e-20;
$v = 1 / $v;
$delta *= $v;
if ($delta > 10) $delta = 10;
if ($delta < -10) $delta = -10;
$a = 2 * log($vol[$i]);
$A = $a;
if ($delta * $delta > $rd[$i] * $rd[$i] + $v)
$B = log($delta * $delta - $rd[$i] * $rd[$i] - $v);
else {
for ($k = 1; $k < 100 && g2_f($a - $k * $TAU, $delta, $rd[$i], $v, $a, $TAU) < 0; ++$k)
;
$B = $a - $k * $TAU;
}
$fa = g2_f($A, $delta, $rd[$i], $v, $a, $TAU);
$fb = g2_f($B, $delta, $rd[$i], $v, $a, $TAU);
while ($fa * $fb > 0) {
$B -= $TAU;
$fb = g2_f($B, $delta, $rd[$i], $v, $a, $TAU);
}
$k = 0;
while (abs($B - $A) > 1e-6 && $k < 100) {
if (!is_finite($fa) || !is_finite($fb)) break;
if (abs($fa - $fb) < 1e-15) break;
$C = $A + ($A - $B) * $fa / ($fb - $fa);
$fc = g2_f($C, $delta, $rd[$i], $v, $a, $TAU);
if ($fc * $fb <= 0) {
$A = $B;
$fa = $fb;
}
else
$fa = $fa / 2;
$B = $C;
$fb = $fc;
++$k;
}
$new_vol[$i] = exp(($A + $B) / 4);
$new_rd[$i] = sqrt($rd[$i] * $rd[$i] + $new_vol[$i] * $new_vol[$i]);
$new_rd[$i] = 1 / sqrt(1 / $v + 1 / $new_rd[$i] / $new_rd[$i]);
$new_rating[$i] = $rating[$i] + $delta / $v * $new_rd[$i] * $new_rd[$i];
$new_rating[$i] = $new_rating[$i] * 173.7178 + 1500;
$new_rd[$i] *= 173.7178;
}
}
原帖:
WyOJ 现在切换到了新的 和 Codeforces 算法相同的 Rating 系统。
具体算法:
写的很着急,如果有问题可以跟帖。
同时,所有 Rating 已经重新计算。现在的 Rating 应该是非常合理的。
新的 Rating 计算函数,采用 Codeforces 算法。
具体算法是:
设参赛前每人的 Rating 是 $r_i$, 比赛的最终排名是 $R_i$,那么
首先承认:在先前 Rating 的基础上,i 战胜 j 的概率是 $P_ij = \dfrac{1}{1 + 10^{\dfrac{r_j - r_i}{400}}}$
立即得到 i 的期望排名 $E_i = \sum_{j \ne i} P_{ji} + 1$
显然,真正的排名和期望排名之间的差距,就是 rating delta 的来源。
我们取 $S_i = \sqrt{E_i R_i}$,二分出一个 u 使得计算出的 $S_i = E_i$,rating 应当向 u 的方向变化。
取 $\delta = \dfrac{u + r_i}{2}$,随后我们对 $\delta$ 进行微调。
第一次微调:取 $d = \dfrac{-1 - \sum_{i} \delta_i}{n}$,将所有人的 \delta 加上 d。
第二次微调:取排名前 $s = \min{n, 4\sqrt n}$ 高的人,让这些人的 rating 变化量之和为零,得到 d。
随后再将所有人的 $\delta$ 加上 d,得到最终的 rating。
/*
* 新的 Rating 计算函数,采用 Codeforces 算法。
* 具体算法是:
* 设参赛前每人的 Rating 是 r_i, 比赛的最终排名是 R_i,那么
* 首先承认:在先前 Rating 的基础上,i 战胜 j 的概率是 P_ij = \dfrac{1}{1 + 10^{\dfrac{r_j - r_i}{400}}}
* 立即得到 i 的期望排名 E_i = \sum_{j \ne i} P_ji + 1
* 显然,真正的排名和期望排名之间的差距,就是 rating delta 的来源。
* 我们取 S_i = \sqrt{E_i R_i},二分出一个 u 使得计算出的 S_i = E_i,rating 应当向 u 的方向变化。
* 取 \delta = \dfrac{u + r_i}{2},随后我们对 \delta 进行微调。
* 第一次微调:取 d = \dfrac{-1 - \sum_{i} \delta_i}{n},将所有人的 \delta 加上 d。
* 第二次微调:取排名前 s = \min{n, 4\sqrt n} 高的人,让这些人的 rating 变化量之和为零,得到 d。
* 随后再将所有人的 \delta 加上 d,得到最终的 rating。
* */
function calcRatingX($standings) {
$n = count($standings);
$rating = array();
$delta = array();
$ds = 0;
for ($i = 0; $i < $n; ++$i)
$rating[$i] = $standings[$i][2][1];
for ($i = 0; $i < $n; ++$i) {
$l = 0;
$r = 4000;
while ($l <= $r) {
$mid = ($l + $r) / 2;
$e = 1;
for ($j = 0; $j < $n; ++$j)
if ($i != $j)
$e += 1 / (1 + pow(10, ($mid - $rating[$j]) / 400));
$s = sqrt($e * ($i + 1));
if ($e <= $s)
$r = $mid - 1;
else
$l = $mid + 1;
}
$delta[$i] = (($l + $r) / 2 - $rating[$i]) / 2;
$ds += $delta[$i];
}
$ds = (-1 - $ds) / $n;
for ($i = 0; $i < $n; ++$i)
$delta[$i] += $ds;
$s = min($n, 4 * sqrt($n));
$ds = 0;
for ($i = 0; $i < $s; ++$i)
$ds += $delta[$i];
$ds = -$ds / $s;
for ($i = 0; $i < $s; ++$i)
$delta[$i] += $ds;
$R = array();
for ($i = 0; $i < $n; ++$i)
$R[$i] = ceil($rating[$i] + $delta[$i]);
return $R;
}
显然,我的勋章是现在全站最帅的,没有之一。
如果没有刷新的话,可以按 ctrl-shift-R 强制刷新一次。
我们添加了三种特别勋章:Pro、Max、Ultra。我现在是 Ultra。
并且,现在,组管理员可以给每个组成员颁发勋章了!在“组管理”界面,可以找到入口。
组管理员添加的勋章,只能是普通颜色,不能是 Pro、Max、Ultra 这种炫酷颜色。后三者只能由管理员颁发。
如果想要勋章,可以在本帖子下跟帖!
但是十分尴尬的是,更新勋章的时候不小心把所有人的格言都设成了 deepblue。。回滚数据库有点麻烦。大家自己重新更新吧。
-- upd 20:43
增加了 Pro Max,本来打算垄断的,结果被抢注了,不值钱了。Pro Max 不给注册!!!
WyOJ 小资历可能不知道,OJ 的普通用户也是可以上传自己的题目的。
具体方法是:
点击右上角的用户名,打开“组管理”菜单。
在“我的组”中,每个普通用户可以创建一个独属于自己的组,但仅能创建一个。
创建完毕后,点击“管理”,进入组管理界面。
可以在左侧进行“编辑昵称”、“成员管理”、“题目管理”、“空间管理”。
WyOJ 组的管理很简单:每个组有管理员(也就是超级用户)和普通成员,管理员可以创建新题,而普通成员不能。
创建题目的方法:在“题库”界面中,点入“团队 group_XXX 题目”,就可以进入组题目的列表。页面最下方点击“添加新题”即可。
创建完题目后,点进去并进入管理界面。在“编辑”标签页可以编辑题面,“数据”界面可以上传数据。
WyOJ 的题目数据配置需要一个 problem.conf 配置文件。这个配置文件,可以通过运行 https://ryp.wyoj.org.cn/post/29 中的 Python 脚本来创建。在数据目录下,只需要输入时间和空间限制,就可以得到一个 problem.conf 文件。然后将所有数据包括这个文件打包成 ZIP 压缩包,再点击“数据”中的上传数据。
如果你不想自己创建 problem.conf,也有一种更直观但是可能存在一些小问题的方法:首先按照同样的方法上传完数据,然后在“数据”标签页点击“试题配置”。对比函数一般填“单行字符串序列(wcmp)”即可。额外数据点数和样例数量,都填写 0。
数据上传完后,一定要点击“校验配置并同步”,WyOJ 才会真正配置你的题目。
组中题目默认是私密的,也就是只有组中的人能看见。管理员可以将其改为“公开”,于是所有人都可以看到这道题,不管是否在组中。
当然,WyOJ 管理员拥有组的全部权限,即使你并没有把我加进组中。
题目管理中,你可以看到已经创建的题目。
空间管理中,你可以看到所有题目空间的总和。这个空间指的是题目数据压缩包的空间之和。
每个组创建题目的数量是没有限制的,但是空间有限。超出了空间就无法再创建新的题目,只能选择删除旧题或者和管理员申请扩容。一般管理员是会同意的。
每个组默认的空间配额是 500MB,解压后大概能到数个 G。对于几乎所有人,这是足够的。整个 WyOJ 现在也只有 10G 的题目数据压缩包。
我们非常欢迎大家上传自己的题目,并相互分享,交流做法。
大家可以将做法发到博客系统上。
当前,必须联系管理员手动开通后才能使用博客系统。具体联系方法很简单,直接在 WyOJ 激活群中 @ryp 联系处理即可。
或者也可以私聊加 ryp:QQ 2681243014。