Problem SettingPolygon guide

Problem Preparation Checklist

Go through every section before you send a problem for review. Your progress is saved in this browser.

Scoreboard

Finish a section to get its balloon
0 Items done
0%
0 Sections AC

  • Use standard input and output in every problem.
  • File names may use only lowercase letters, digits, and _. No other characters are allowed.
  • Compile every source file with cpp17 for C++ or java21 for Java. This includes solutions, generators, the validator, the checker, and the interactor.
  • Do not use freopen, #ifndef ONLINE_JUDGE, or any other local debug code in any source file.
  • In the Files tab, turn on auto update for testlib.h.
  • Add a #topic tag for the main algorithm, for example #binary_search.
  • Add a #difficulty tag, for example #div2-A or #div2-B.

  • The problem title must not contain characters that break CSV, such as commas or semicolons.
  • Keep the statement short and simple. Skip stories, because they may change later.
  • Write every variable in $$LaTeX math mode$$.
  • For multiplication, use \times. Do not use \cdot, *, or the letter x.
  • If the statement uses a known term such as permutation, Fibonacci number, or MEX, define it in a \footnote{...}.
  • Save every image as EPS, not JPG or PNG. Prefer black and white, and use color only when you need it.
  • Check the LaTeX and formatting carefully.
  • Run the text through GPT and Grammarly to catch mistakes.
  • The statement must render to PDF and HTML on Polygon.

  • Call registerValidation(argc, argv) at the start of main.
  • Check the full input format and every constraint from the statement.
  • Write large numbers with digit separators, for example 1'000'000 instead of 1000000.
  • In multi-test problems, call setTestCase(i) at the start of each test case. Errors then show which test case failed.
  • Add validator tests that show the validator is correct.

  • Prefer multiple test cases in one input. A single test case problem is fine too. In the generator, split the total size with rnd.partition(T, sumN, 1), so the sizes add up to exactly sumN.
  • Every variable must hit its minimum and its maximum in at least one test. Otherwise Polygon warns Variable "t" didn't hit minimal value.
  • Add worst-case tests that make slow solutions fail, for example maximum n and q with every query on the whole array. The TLE solution must go over the time limit by a clear margin. Include the largest possible input and output.
  • Add special shapes, such as sorted, reversed, all equal, alternating, and blocks. When it makes sense, make the answer as small and as large as possible.
  • No two tests may be equal, including samples and hand-written tests. Polygon rejects equal tests.
  • Add 1 or 2 hand-written edge cases, and mark at least one test as Use in statements.
  • Keep the total number of tests at 30 or fewer.
  • Make large tests with generators, and use more than one when you can. Build tests from the problem's logic, not only random values. For example, make YES and NO cases on purpose.
  • Run generators from the script in the Tests tab. Call each one by its file name without .cpp: generator.cpp runs as generator, not gen.
  • Start every generator with registerGen(argc, argv, 1). The 1 is the random version, not a seed. Read sizes and limits as flags with opt<int>("n"). Never hard-code them, so the script can set each variable to its minimum and its maximum.
  • Polygon runs the script again on every build, so it must make the same tests every time. Take all randomness from testlib: rnd.next, rnd.partition, rnd.perm, rnd.distinct, and shuffle(begin, end). Never use rand, srand, time, random_shuffle, std::shuffle, or anything from <random> or <chrono>.
  • Never call rnd twice in one expression, like println(rnd.next(1, n), rnd.next(1, n)). Each compiler can run the two calls in a different order, so save each value in a variable first. For the same reason, do not print an unordered_set or unordered_map in its own order, or depend on how std::sort orders equal keys.
  • When two script lines would be the same, add a different number to each: generator -n 100 1, generator -n 100 2. testlib seeds its random from the whole line, so a new number gives a new test. In a loop, use the loop variable: <#list 1..20 as s> generator -n 100 ${s} > $ </#list>. Put the number before any flag with no value: in generator -small 1, testlib reads 1 as the value of -small.
  • Once the tests are final, do not change generator code the script already uses. One extra rnd call changes every test that runs that code. To add tests, add a new mode instead.
  • Run a stress test: compare the main solution with a brute force on many small random tests.

  • An accepted solution in both C++ and Java.
  • The main accepted solution should be a clear, normal implementation, not a heavily optimized one. Do not set the time limit from best-case performance.
  • A second accepted solution by a different author or with a different approach.
  • One TLE solution that is slow on purpose.
  • One WA solution that gives wrong output.
  • There must be no compiler warnings.
  • Do not use optimization pragmas, such as #pragma GCC optimize or target pragmas.
  • The Java class name must match the file name exactly.

  • The default checker is wcmp. It compares the output token by token. Use it for strings, mixed output, and most other problems.
  • If wcmp does not fit the output, pick another standard checker: lcmpLines. Ignores extra whitespace. fcmpLines. Does not ignore whitespace. ncmpOne or more 64-bit integers. Ignores whitespace. hcmpOne huge integer. yesnoOne yes or no, in any letter case. nyesnoZero or more yes or no answers, in any letter case. rcmp4rcmp6rcmp9One or more real numbers. The absolute or relative error can be up to 1E-4, 1E-6, or 1E-9.
  • Turn on auto update for the checker.
  • A custom checker must call registerTestlibCmd(argc, argv) at the start of main.
  • In a multi-test checker, call setTestCase(i) at the start of each test case.
  • Add checker tests that show the checker works. Do this even for a standard checker like wcmp.

  • Setup
  • Name the file interactor.cpp, all in lowercase.
  • Call registerInteraction(argc, argv) at the start of main.
  • inf is the test input. ouf is the participant's output. cout sends data to the participant. tout writes a log for the checker.
  • quitf(_ok, ...) means correct. quitf(_wa, ...) means wrong answer or query limit exceeded. quitf(_pe, ...) means bad output format. quitf(_fail, ...) means a bug in the judge, not the participant's fault.
  • Talking to the participant
  • Flush after every response with cout.flush() or endl. If you forget, the verdict is ILE (Idleness Limit Exceeded), not WA.
  • If a query is invalid or the query limit is exceeded, send -1 to the participant first. Then call quitf(_wa, "reason").
  • The Interaction section of the statement must say this: after an invalid query or too many queries, the participant gets -1 and must stop right away.
  • Participant solutions
  • Solutions must read each response as a string, not a char. A char reads -1 as two parts, - and 1, so the solution misses the signal. On Codeforces it then gets TLE instead of WA.
  • Do not use cin.tie(nullptr) in interactive solutions. It unties cin from cout, so the output is no longer flushed before each read, and the verdict is ILE.
  • If a brute-force solution goes over the query limit, the interactor calls quitf(_wa). In the Polygon Solutions tab, tag brute.cpp as Wrong Answer, not TLE.
  • Multiple tests
  • Prefer a single test for interactive problems. If you need multiple tests: Read t from inf and send it to the participant right away. If you skip this, the participant waits on cin >> t and crashes. Call setTestCase(tc + 1) as the first line of each loop iteration. Call quitf(_ok, ...) once after the loop, not inside it.
  • Checker for interactive problems
  • A checker is optional. If the interactor already gives every verdict with quitf, you do not need one. Add a checker only when you need extra checks after the interactor finishes.
  • If you use a checker, write the values it needs to tout before quitf, for example tout << secret << "\n" << answer << "\n" << queries_used << "\n". The checker reads them from its own ouf stream with ouf.readInt.
  • In that checker, call ouf.readEoln() after each integer. If you skip it, the \n stays in the buffer and readEof() fails with PE.

  • Each problem needs a tutorial that explains the full solution.
  • Write the full explanation in the Polygon tutorial, or write a short summary there and add a shared Google Docs or Google Slides link.
  • The tutorial must render to PDF and HTML on Polygon.

All sections accepted

Every item is done. The problem is ready for review.