您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
RationalModConverter https://github.com/catupper/RationalModConverter/ の userjs 版です.
当前为
// ==UserScript== // @name RationalModConverterUserJS // @namespace iilj // @version 2021.5.5.0 // @description RationalModConverter https://github.com/catupper/RationalModConverter/ の userjs 版です. // @author iilj // @match https://atcoder.jp/contests/*/tasks/* // @match https://yukicoder.me/problems/* // @grant none // ==/UserScript== class RationalModConverter { static re = /\d+/; static SPAN_CLASS_NAME = 'rmc-result-span'; /** @type {[string, number][]} */ static str2mod = [ ['998244353', 998244353], ['1000000007', 1000000007], ['10^{9}+7', 1000000007], ['10^9+7', 1000000007], ['109+7', 1000000007], ]; constructor() { /** @type {HTMLElement | undefined} */ let root = undefined; if (location.hostname === 'atcoder.jp') { root = document.getElementById('task-statement'); } else if (location.hostname === 'yukicoder.me') { root = document.getElementById('content'); } if (root === undefined) return; this.mod = this.searchMod(root); if (this.mod === undefined) return; this.dfsNodes(root); } /** @type {(root: HTMLElement) => (number | undefined)} */ searchMod(root) { /** @type {number | undefined} */ let mod = undefined; const scripts = root.querySelectorAll('var > script'); for (let i = 0; i < scripts.length; i++) { if ((mod = this.serarchModSub(scripts[i])) !== undefined) return mod; } const mjxs = root.querySelectorAll('mjx-assistive-mml'); for (let i = 0; i < mjxs.length; i++) { if ((mod = this.serarchModSub(mjxs[i])) !== undefined) return mod; } return undefined; } /** @type {(element: HTMLElement) => (number | undefined)} */ serarchModSub(element) { const txt = element.textContent; const ret = RationalModConverter.str2mod.find(([pat, _]) => txt.indexOf(pat) !== -1); if (ret === undefined) return undefined; return ret[1]; } /** @type {(root: HTMLElement, mod: number) => void} */ dfsNodes(root) { if (root.classList.contains(RationalModConverter.SPAN_CLASS_NAME)) return; root.childNodes.forEach(childNode => { switch (childNode.nodeName) { case 'SPAN': case 'DIV': case 'P': case 'PRE': case 'UL': case 'OL': case 'LI': case 'SECTION': this.dfsNodes(childNode); break; case '#text': this.rewriteTextNode(childNode, root); break; default: break; } }); } /** @type {(node: Text, parent: HTMLElement, mod: number) => void} */ rewriteTextNode(node, parent) { const match = RationalModConverter.re.exec(node.nodeValue); if (match !== null) { const len = match.index + (match[0].length); const nextNode = node.splitText(len); const parsed = parseInt(match[0]); if (parsed < this.mod && parsed * parsed * 2 > this.mod) { const w = RationalModConverter.reconstruct(parsed, this.mod); const newSpan = document.createElement('span'); newSpan.innerText = (w[1] === 1) ? ` ${w[0]}` : ` ${w[0]}/${w[1]}`; newSpan.style.color = 'red'; newSpan.style.marginRight = '0.5rem'; newSpan.classList.add(RationalModConverter.SPAN_CLASS_NAME); parent.insertBefore(newSpan, nextNode); // console.log(parsed, w); } this.rewriteTextNode(nextNode, parent); } } /** * Rational reconstruction (mathematics) - Wikipedia * https://en.wikipedia.org/wiki/Rational_reconstruction_(mathematics) * @type {(n: number, mod: number) => [number, number]} **/ static reconstruct(n, mod) { /** @type{[number, number]} */ let v = [mod, 0]; /** @type{[number, number]} */ let w = [n, 1]; while (w[0] * w[0] * 2 > mod) { const q = Math.floor(v[0] / w[0]); const z = [v[0] - q * w[0], v[1] - q * w[1]]; v = w; w = z; } if (w[1] < 0) { w[0] *= -1; w[1] *= -1; } return w; } } (() => { 'use strict'; window.addEventListener('load', () => { const r = new RationalModConverter(); }); })();