Constraints Emphasizer

AtCoderで入力値の制約が極端な時に目立たせる。(inspired by Time Limit Emphasizer by https://github.com/Ogtsn99)

Από την 06/07/2025. Δείτε την τελευταία έκδοση.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name        Constraints Emphasizer
// @namespace   https://github.com/TrueRyoB
// @version      1.3
// @description AtCoderで入力値の制約が極端な時に目立たせる。(inspired by Time Limit Emphasizer by https://github.com/Ogtsn99)
// @include     https://atcoder.jp/contests/*/tasks/*
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @author TrueRyoB
// @license MIT
// ==/UserScript==

const styles = [
    { ub: 10, className: 'dneg-perm' },
    { ub: 20, className: 'dneg-2pn' },
    { ub: 30, className: 'dneg-2pmdiv3' },
    { ub: 100, className: 'dneg-np4' },
    { ub: 300, className: 'dneg-np3' },
    { ub: 1000, className: 'dneg-np2' },
    { ub: 1000000, className: 'dneg-nlogn' },
    { ub: 100000000, className: 'dneg-n' },
    { ub: 1000000000000, className: 'dneg-logn' },
];

$('<style>')
    .prop('type', 'text/css')
    .html(`
        .dneg-c { color:#e2345; font-weight:1000; }
        .dneg-perm { color:#492ed1; font-weight:700; }
        .dneg-2pn { color:#492ed1; font-weight:700; }
        .dneg-2pmdiv3 { color:#492ed1; font-weight:700; }
        .dneg-np4 { color:#2ed192; font-weight:700; }
        .dneg-np3 { color:#2ed192; font-weight:700; }
        .dneg-np2 { color:#2ed192; font-weight:700; }
        .dneg-nlogn { }
        .dneg-n { }
        .dneg-logn { color: #e23454; font-weight:700;}
    `)
    .appendTo('head');


const $container = $('section h3:contains("制約")');
$container.next('ul').find('li').each(function () {
    const annotation = $(this).find('annotation[encoding="application/x-tex"]').text();
    console.log("new annotation:", annotation);
    const bound = extractMinMax(annotation);
    
    let found=false;
    for (const style of styles) {
        if(style.ub <= bound.max) {
            $(this).addClass(style.className);found=true;break;
        }
    }
    if(!found) $(this).addClass('dneg-c');
});

function extractMinMax(annotation) {
    const match = annotation.match(/(\d+)\s*\\leq\s*.+?\s*\\leq\s*(.+)/);
    if (!match) return null;

    const min = parseInt(match[1], 10);
    const rawMax = match[2].trim();

    let max;

    const funcMatch = rawMax.match(/\\(min|max)\s*\(([^)]+)\)/);
    if (funcMatch) {
        const [, funcType, args] = funcMatch;
        const values = args.split(',').map(s => s.trim());

        let numericValues = values.map(val => {
            const expMatch = val.match(/(\d+)\s*\\times\s*10\^\{?(\d+)\}?/);
            if (expMatch) {
                return parseInt(expMatch[1], 10) * Math.pow(10, parseInt(expMatch[2], 10));
            }
            const plainNum = val.match(/^\d+$/);
            return plainNum ? parseInt(val, 10) : null;
        }).filter(v => v !== null);

        if (numericValues.length === 0) return null;

        max = funcType === "min"
            ? Math.min(...numericValues)
            : Math.max(...numericValues);
    } else {
        const expMatch = rawMax.match(/(\d+)\s*\\times\s*10\^\{?(\d+)\}?/);
        if (expMatch) {
            max = parseInt(expMatch[1], 10) * Math.pow(10, parseInt(expMatch[2], 10));
        } else {
            const plainNum = rawMax.match(/^\d+$/);
            max = plainNum ? parseInt(rawMax, 10) : null;
        }
    }

    if (isNaN(min) || isNaN(max)) return null;
    return { min, max };
}