rbx.cp 0.7.0__py3-none-any.whl → 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rbx/box/cd.py +2 -2
- rbx/box/cli.py +87 -33
- rbx/box/code.py +133 -84
- rbx/box/contest/build_contest_statements.py +2 -2
- rbx/box/contest/contest_package.py +1 -1
- rbx/box/contest/main.py +29 -2
- rbx/box/environment.py +140 -80
- rbx/box/formatting.py +2 -1
- rbx/box/global_package.py +74 -0
- rbx/box/package.py +11 -24
- rbx/box/packaging/__init__.py +0 -0
- rbx/box/packaging/boca/__init__.py +0 -0
- rbx/box/packaging/polygon/packager.py +3 -3
- rbx/box/presets/__init__.py +369 -53
- rbx/box/presets/lock_schema.py +42 -2
- rbx/box/presets/schema.py +4 -0
- rbx/box/remote.py +21 -2
- rbx/box/retries.py +3 -2
- rbx/box/sanitizers/warning_stack.py +5 -5
- rbx/box/solutions.py +37 -25
- rbx/box/statements/build_statements.py +6 -6
- rbx/box/statements/builders.py +1 -1
- rbx/box/stats.py +10 -0
- rbx/box/stresses.py +47 -66
- rbx/box/stressing/finder_parser.py +11 -16
- rbx/box/tasks.py +33 -22
- rbx/box/testcase_utils.py +3 -3
- rbx/box/tooling/boca/scraper.py +1 -1
- rbx/grading/caching.py +98 -47
- rbx/grading/debug_context.py +31 -0
- rbx/grading/grading_context.py +96 -0
- rbx/grading/judge/cacher.py +93 -21
- rbx/grading/judge/sandbox.py +8 -4
- rbx/grading/judge/sandboxes/isolate.py +3 -2
- rbx/grading/judge/sandboxes/stupid_sandbox.py +3 -2
- rbx/grading/judge/sandboxes/timeit.py +1 -1
- rbx/grading/judge/storage.py +170 -35
- rbx/grading/profiling.py +126 -0
- rbx/grading/steps.py +46 -17
- rbx/grading/steps_with_caching.py +52 -26
- rbx/resources/envs/default.rbx.yml +2 -3
- rbx/resources/envs/isolate.rbx.yml +2 -3
- rbx/resources/presets/default/contest/.gitignore +6 -0
- rbx/resources/presets/default/contest/contest.rbx.yml +14 -1
- rbx/resources/presets/default/contest/statement/contest.rbx.tex +24 -86
- rbx/resources/presets/default/contest/statement/instructions.tex +40 -0
- rbx/resources/presets/default/contest/statement/logo.png +0 -0
- rbx/resources/presets/default/env.rbx.yml +67 -0
- rbx/resources/presets/default/preset.rbx.yml +6 -2
- rbx/resources/presets/default/problem/.gitignore +1 -1
- rbx/resources/presets/default/problem/problem.rbx.yml +12 -8
- rbx/resources/presets/default/shared/contest_template.rbx.tex +57 -0
- rbx/resources/presets/default/shared/icpc.sty +322 -0
- rbx/resources/presets/default/shared/problem_template.rbx.tex +57 -0
- rbx/submitors/codeforces.py +3 -2
- rbx/test.py +1 -1
- rbx/utils.py +6 -1
- {rbx_cp-0.7.0.dist-info → rbx_cp-0.9.0.dist-info}/METADATA +4 -1
- {rbx_cp-0.7.0.dist-info → rbx_cp-0.9.0.dist-info}/RECORD +67 -58
- rbx/resources/presets/default/contest/statement/olymp.sty +0 -250
- rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -42
- rbx/resources/presets/default/problem/statement/olymp.sty +0 -250
- rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -89
- /rbx/resources/presets/default/problem/{gen.cpp → gens/gen.cpp} +0 -0
- /rbx/resources/presets/default/problem/{tests → manual_tests}/samples/000.in +0 -0
- /rbx/resources/presets/default/problem/{tests → manual_tests}/samples/001.in +0 -0
- /rbx/resources/presets/default/problem/{random.py → testplan/random.py} +0 -0
- /rbx/resources/presets/default/problem/{random.txt → testplan/random.txt} +0 -0
- {rbx_cp-0.7.0.dist-info → rbx_cp-0.9.0.dist-info}/LICENSE +0 -0
- {rbx_cp-0.7.0.dist-info → rbx_cp-0.9.0.dist-info}/WHEEL +0 -0
- {rbx_cp-0.7.0.dist-info → rbx_cp-0.9.0.dist-info}/entry_points.txt +0 -0
rbx/grading/profiling.py
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
import contextvars
|
2
|
+
import functools
|
3
|
+
import math
|
4
|
+
import threading
|
5
|
+
import time
|
6
|
+
|
7
|
+
ALL_CONTEXTS_BY_NAME = {}
|
8
|
+
_ALL_CONTEXTS_BY_NAME_LOCK = threading.Lock()
|
9
|
+
|
10
|
+
|
11
|
+
@functools.cache
|
12
|
+
def _get_threadsafe_context(name: str) -> 'Context':
|
13
|
+
with _ALL_CONTEXTS_BY_NAME_LOCK:
|
14
|
+
if name not in ALL_CONTEXTS_BY_NAME:
|
15
|
+
ALL_CONTEXTS_BY_NAME[name] = Context(name)
|
16
|
+
return ALL_CONTEXTS_BY_NAME[name]
|
17
|
+
|
18
|
+
|
19
|
+
class Distribution:
|
20
|
+
def __init__(self):
|
21
|
+
self.values = []
|
22
|
+
|
23
|
+
def add(self, value: float):
|
24
|
+
self.values.append(value)
|
25
|
+
|
26
|
+
def mean(self) -> float:
|
27
|
+
return sum(self.values) / len(self.values)
|
28
|
+
|
29
|
+
def median(self) -> float:
|
30
|
+
return sorted(self.values)[len(self.values) // 2]
|
31
|
+
|
32
|
+
def stddev(self) -> float:
|
33
|
+
mean = self.mean()
|
34
|
+
return math.sqrt(sum((x - mean) ** 2 for x in self.values) / len(self.values))
|
35
|
+
|
36
|
+
|
37
|
+
class Context:
|
38
|
+
def __init__(self, name: str):
|
39
|
+
self.name = name
|
40
|
+
self._lock = threading.Lock()
|
41
|
+
self.distributions = {}
|
42
|
+
self.counters = {}
|
43
|
+
|
44
|
+
def add_to_distribution(self, name: str, value: float):
|
45
|
+
with self._lock:
|
46
|
+
if name not in self.distributions:
|
47
|
+
self.distributions[name] = Distribution()
|
48
|
+
self.distributions[name].add(value)
|
49
|
+
|
50
|
+
def add_to_counter(self, name: str):
|
51
|
+
with self._lock:
|
52
|
+
if name not in self.counters:
|
53
|
+
self.counters[name] = 0
|
54
|
+
self.counters[name] += 1
|
55
|
+
|
56
|
+
def print_summary(self):
|
57
|
+
with self._lock:
|
58
|
+
print(f'{self.name}:')
|
59
|
+
for name, distribution in sorted(self.distributions.items()):
|
60
|
+
print(f' ~ {name}: {distribution.mean():.2f}')
|
61
|
+
for name, count in sorted(self.counters.items()):
|
62
|
+
print(f' + {name}: {count}')
|
63
|
+
|
64
|
+
|
65
|
+
profiling_stack_var = contextvars.ContextVar(
|
66
|
+
'profiling_stack', default=[_get_threadsafe_context('root')]
|
67
|
+
)
|
68
|
+
|
69
|
+
|
70
|
+
def _push_profiling_stack(name: str):
|
71
|
+
return profiling_stack_var.set(
|
72
|
+
profiling_stack_var.get() + [_get_threadsafe_context(name)]
|
73
|
+
)
|
74
|
+
|
75
|
+
|
76
|
+
class PushContext:
|
77
|
+
def __init__(self, name: str):
|
78
|
+
self.name = name
|
79
|
+
self.token = None
|
80
|
+
|
81
|
+
def __enter__(self):
|
82
|
+
self.token = _push_profiling_stack(self.name)
|
83
|
+
return profiling_stack_var.get()[-1]
|
84
|
+
|
85
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
86
|
+
if self.token is not None:
|
87
|
+
profiling_stack_var.reset(self.token)
|
88
|
+
|
89
|
+
|
90
|
+
def print_summary():
|
91
|
+
print('\n' + ('-') * 3 + '\n')
|
92
|
+
with _ALL_CONTEXTS_BY_NAME_LOCK:
|
93
|
+
for context in ALL_CONTEXTS_BY_NAME.values():
|
94
|
+
context.print_summary()
|
95
|
+
|
96
|
+
|
97
|
+
### Public API
|
98
|
+
|
99
|
+
|
100
|
+
class Profiler:
|
101
|
+
def __init__(self, name: str, start: bool = False):
|
102
|
+
self.name = name
|
103
|
+
self.start_time = 0
|
104
|
+
if start:
|
105
|
+
self.start()
|
106
|
+
|
107
|
+
def start(self):
|
108
|
+
self.start_time = time.monotonic()
|
109
|
+
return self
|
110
|
+
|
111
|
+
def stop(self):
|
112
|
+
self.end_time = time.monotonic()
|
113
|
+
self.duration = self.end_time - self.start_time
|
114
|
+
for context in profiling_stack_var.get():
|
115
|
+
context.add_to_distribution(self.name, self.duration)
|
116
|
+
|
117
|
+
def __enter__(self):
|
118
|
+
return self.start()
|
119
|
+
|
120
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
121
|
+
self.stop()
|
122
|
+
|
123
|
+
|
124
|
+
def add_to_counter(name: str):
|
125
|
+
for context in profiling_stack_var.get():
|
126
|
+
context.add_to_counter(name)
|
rbx/grading/steps.py
CHANGED
@@ -20,9 +20,10 @@ from rich.text import Text
|
|
20
20
|
from rbx import utils
|
21
21
|
from rbx.config import get_bits_stdcpp, get_jngen, get_testlib
|
22
22
|
from rbx.console import console
|
23
|
-
from rbx.grading import processing_context
|
23
|
+
from rbx.grading import grading_context, processing_context
|
24
|
+
from rbx.grading.judge.cacher import FileCacher
|
24
25
|
from rbx.grading.judge.sandbox import SandboxBase, SandboxParams
|
25
|
-
from rbx.grading.judge.storage import
|
26
|
+
from rbx.grading.judge.storage import copyfileobj
|
26
27
|
from rbx.grading.limits import Limits
|
27
28
|
|
28
29
|
MAX_STDOUT_LEN = 1024 * 1024 * 128 # 128 MB
|
@@ -139,6 +140,8 @@ class GradingFileInput(BaseModel):
|
|
139
140
|
digest: Optional[DigestHolder] = None
|
140
141
|
# Whether the destination file should be marked as an executable.
|
141
142
|
executable: bool = False
|
143
|
+
# Whether to track file through its hash (disable for optimization).
|
144
|
+
hash: bool = True
|
142
145
|
|
143
146
|
|
144
147
|
class GradingFileOutput(BaseModel):
|
@@ -161,15 +164,15 @@ class GradingFileOutput(BaseModel):
|
|
161
164
|
# Whether to touch the file before the command runs.
|
162
165
|
touch: bool = False
|
163
166
|
|
164
|
-
def get_file(self,
|
167
|
+
def get_file(self, cacher: FileCacher) -> Optional[IO[bytes]]:
|
165
168
|
if self.dest is not None:
|
166
169
|
if self.optional and not self.dest.exists():
|
167
170
|
return None
|
168
171
|
return self.dest.open('rb')
|
169
172
|
if self.digest is not None and self.digest.value is not None:
|
170
|
-
if self.optional and not
|
173
|
+
if self.optional and not cacher.exists(self.digest.value):
|
171
174
|
return None
|
172
|
-
return
|
175
|
+
return cacher.get_file(self.digest.value)
|
173
176
|
raise ValueError('No file to get')
|
174
177
|
|
175
178
|
|
@@ -308,11 +311,14 @@ def _process_input_artifacts(artifacts: GradingArtifacts, sandbox: SandboxBase):
|
|
308
311
|
|
309
312
|
|
310
313
|
def _process_output_artifacts(
|
311
|
-
artifacts: GradingArtifacts,
|
314
|
+
artifacts: GradingArtifacts,
|
315
|
+
sandbox: SandboxBase,
|
312
316
|
) -> bool:
|
313
317
|
for output_artifact in artifacts.outputs:
|
314
318
|
if output_artifact.hash and output_artifact.digest is None:
|
315
|
-
|
319
|
+
if not grading_context.is_no_cache():
|
320
|
+
# If cache is enabled, track this file in cache.
|
321
|
+
output_artifact.digest = DigestHolder()
|
316
322
|
if not sandbox.file_exists(output_artifact.src):
|
317
323
|
if output_artifact.optional:
|
318
324
|
continue
|
@@ -322,21 +328,43 @@ def _process_output_artifacts(
|
|
322
328
|
return False
|
323
329
|
|
324
330
|
if output_artifact.digest is not None:
|
325
|
-
|
326
|
-
|
327
|
-
|
331
|
+
# Put it in the cache, possibly compressing it if it's an executable.
|
332
|
+
with grading_context.compression(
|
333
|
+
use_compression=True,
|
334
|
+
when=output_artifact.executable,
|
335
|
+
):
|
336
|
+
output_artifact.digest.value = sandbox.get_file_to_storage(
|
337
|
+
output_artifact.src, trunc_len=output_artifact.maxlen
|
338
|
+
)
|
328
339
|
if output_artifact.dest is None:
|
329
340
|
continue
|
330
341
|
dst: pathlib.Path = artifacts.root / output_artifact.dest
|
331
342
|
# Ensure dst directory exists.
|
343
|
+
|
332
344
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
345
|
+
|
346
|
+
if (
|
347
|
+
output_artifact.digest is not None
|
348
|
+
and output_artifact.digest.value is not None
|
349
|
+
and (
|
350
|
+
path_to_symlink := sandbox.file_cacher.path_for_symlink(
|
351
|
+
output_artifact.digest.value
|
339
352
|
)
|
353
|
+
)
|
354
|
+
is not None
|
355
|
+
):
|
356
|
+
# File is in the persistent cache, store a symlink to it.
|
357
|
+
dst.unlink(missing_ok=True)
|
358
|
+
dst.symlink_to(path_to_symlink)
|
359
|
+
else:
|
360
|
+
# File is not in the persistent cache, copy it.
|
361
|
+
with dst.open('wb') as f:
|
362
|
+
with sandbox.get_file(output_artifact.src) as sb_f:
|
363
|
+
copyfileobj(
|
364
|
+
sb_f,
|
365
|
+
f,
|
366
|
+
maxlen=output_artifact.maxlen,
|
367
|
+
)
|
340
368
|
if output_artifact.executable:
|
341
369
|
dst.chmod(0o755)
|
342
370
|
return True
|
@@ -495,7 +523,8 @@ def _get_system_bits_stdcpp(command: str) -> Optional[GradingFileInput]:
|
|
495
523
|
if not bits_candidate.is_file():
|
496
524
|
continue
|
497
525
|
return GradingFileInput(
|
498
|
-
src=
|
526
|
+
src=utils.abspath(bits_candidate),
|
527
|
+
dest=pathlib.Path('bits/stdc++.h'),
|
499
528
|
)
|
500
529
|
return None
|
501
530
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Any, Dict, List, Optional, Tuple
|
2
2
|
|
3
|
-
from rbx.grading import steps
|
3
|
+
from rbx.grading import grading_context, profiling, steps
|
4
4
|
from rbx.grading.caching import DependencyCache, NoCacheException
|
5
5
|
from rbx.grading.judge.sandbox import SandboxBase, SandboxParams
|
6
6
|
from rbx.grading.steps import (
|
@@ -27,17 +27,24 @@ def compile(
|
|
27
27
|
artifacts.logs = GradingLogsHolder()
|
28
28
|
|
29
29
|
ok = True
|
30
|
+
cached_profile = profiling.Profiler('steps.compile[cached]', start=True)
|
30
31
|
with dependency_cache(
|
31
32
|
commands, [artifacts], params.get_cacheable_params()
|
32
33
|
) as is_cached:
|
33
|
-
if not is_cached
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
if not is_cached:
|
35
|
+
with profiling.Profiler('steps.compile'):
|
36
|
+
profiling.add_to_counter('steps.compile')
|
37
|
+
ok = steps.compile(
|
38
|
+
commands=commands,
|
39
|
+
params=params,
|
40
|
+
artifacts=artifacts,
|
41
|
+
sandbox=sandbox,
|
42
|
+
)
|
43
|
+
if not ok:
|
44
|
+
raise NoCacheException()
|
45
|
+
else:
|
46
|
+
cached_profile.stop()
|
47
|
+
profiling.add_to_counter('steps.compile[cached]')
|
41
48
|
|
42
49
|
return ok
|
43
50
|
|
@@ -56,16 +63,25 @@ async def run(
|
|
56
63
|
if metadata is not None and metadata.retryIndex is not None:
|
57
64
|
cacheable_params['__retry_index__'] = metadata.retryIndex
|
58
65
|
|
59
|
-
with
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
with grading_context.cache_level(
|
67
|
+
grading_context.CacheLevel.NO_CACHE,
|
68
|
+
when=grading_context.is_compilation_only,
|
69
|
+
):
|
70
|
+
cached_profile = profiling.Profiler('steps.run[cached]', start=True)
|
71
|
+
with dependency_cache([command], [artifacts], cacheable_params) as is_cached:
|
72
|
+
if not is_cached:
|
73
|
+
with profiling.Profiler('steps.run'):
|
74
|
+
profiling.add_to_counter('steps.run')
|
75
|
+
await steps.run(
|
76
|
+
command=command,
|
77
|
+
params=params,
|
78
|
+
artifacts=artifacts,
|
79
|
+
sandbox=sandbox,
|
80
|
+
metadata=metadata,
|
81
|
+
)
|
82
|
+
else:
|
83
|
+
cached_profile.stop()
|
84
|
+
profiling.add_to_counter('steps.run[cached]')
|
69
85
|
return artifacts.logs.run
|
70
86
|
|
71
87
|
|
@@ -91,13 +107,23 @@ async def run_coordinated(
|
|
91
107
|
if solution.metadata is not None and solution.metadata.retryIndex is not None:
|
92
108
|
cacheable_params['solution.__retry_index__'] = solution.metadata.retryIndex
|
93
109
|
|
94
|
-
with
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
110
|
+
with grading_context.cache_level(
|
111
|
+
grading_context.CacheLevel.NO_CACHE,
|
112
|
+
when=grading_context.is_compilation_only,
|
113
|
+
):
|
114
|
+
cached_profile = profiling.Profiler('steps.run_coordinated[cached]', start=True)
|
115
|
+
with dependency_cache(
|
116
|
+
[interactor.command, solution.command],
|
117
|
+
[interactor.artifacts, solution.artifacts],
|
118
|
+
cacheable_params,
|
119
|
+
) as is_cached:
|
120
|
+
if not is_cached:
|
121
|
+
with profiling.Profiler('steps.run_coordinated'):
|
122
|
+
profiling.add_to_counter('steps.run_coordinated')
|
123
|
+
await steps.run_coordinated(interactor, solution)
|
124
|
+
else:
|
125
|
+
cached_profile.stop()
|
126
|
+
profiling.add_to_counter('steps.run_coordinated[cached]')
|
101
127
|
|
102
128
|
return (
|
103
129
|
interactor.artifacts.logs.run,
|
@@ -18,7 +18,7 @@ defaultExecution:
|
|
18
18
|
memoryLimit: 1024 # 1gb
|
19
19
|
languages:
|
20
20
|
- name: "cpp"
|
21
|
-
|
21
|
+
readableName: "C++17"
|
22
22
|
extension: "cpp"
|
23
23
|
compilation:
|
24
24
|
commands:
|
@@ -28,10 +28,9 @@ languages:
|
|
28
28
|
fileMapping:
|
29
29
|
compilable: "compilable.cpp"
|
30
30
|
- name: "py"
|
31
|
-
|
31
|
+
readableName: "Python3"
|
32
32
|
extension: "py"
|
33
33
|
execution:
|
34
34
|
command: "python3 {executable}"
|
35
35
|
fileMapping:
|
36
36
|
executable: "executable.py"
|
37
|
-
|
@@ -18,7 +18,7 @@ defaultExecution:
|
|
18
18
|
memoryLimit: 1024 # 1gb
|
19
19
|
languages:
|
20
20
|
- name: "cpp"
|
21
|
-
|
21
|
+
readableName: "C++17"
|
22
22
|
extension: "cpp"
|
23
23
|
compilation:
|
24
24
|
commands:
|
@@ -28,10 +28,9 @@ languages:
|
|
28
28
|
fileMapping:
|
29
29
|
compilable: "compilable.cpp"
|
30
30
|
- name: "py"
|
31
|
-
|
31
|
+
readableName: "Python3"
|
32
32
|
extension: "py"
|
33
33
|
execution:
|
34
34
|
command: "/usr/bin/python3 {executable}"
|
35
35
|
fileMapping:
|
36
36
|
executable: "executable.py"
|
37
|
-
|
@@ -8,9 +8,22 @@ statements:
|
|
8
8
|
language: "en"
|
9
9
|
path: "statement/contest.rbx.tex"
|
10
10
|
type: "jinja-tex"
|
11
|
-
assets:
|
11
|
+
assets:
|
12
|
+
- "statement/icpc.sty"
|
13
|
+
- "statement/*.png"
|
14
|
+
- "statement/instructions.tex"
|
12
15
|
joiner: {type: "tex2pdf"}
|
13
16
|
override:
|
14
17
|
configure:
|
15
18
|
- type: "rbx-tex" # Convert rbxTeX to TeX
|
16
19
|
template: "statement/template.rbx.tex"
|
20
|
+
- name: "editorial-en"
|
21
|
+
extends: "statement-en"
|
22
|
+
vars:
|
23
|
+
editorial: true
|
24
|
+
watermark: true
|
25
|
+
# Whether to show the problem statement in the editorial.
|
26
|
+
show_problem: false
|
27
|
+
vars:
|
28
|
+
year: 2025
|
29
|
+
date: "2025-06-21"
|
@@ -1,97 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
\usepackage
|
5
|
-
\usepackage
|
6
|
-
|
7
|
-
\
|
8
|
-
\
|
9
|
-
\
|
10
|
-
|
11
|
-
|
12
|
-
\
|
13
|
-
\
|
14
|
-
\
|
15
|
-
\
|
16
|
-
\
|
17
|
-
|
18
|
-
|
19
|
-
%- for problem in problems
|
20
|
-
%- if problem.blocks.preamble is defined
|
21
|
-
\VAR{problem.blocks.preamble}
|
1
|
+
\documentclass[a4paper,11pt]{article}
|
2
|
+
|
3
|
+
\def\lang{\VAR{lang}}
|
4
|
+
\usepackage{icpc}
|
5
|
+
\usepackage{import}
|
6
|
+
|
7
|
+
\def\Year{\VAR{vars.year}}
|
8
|
+
\def\Title{\VAR{contest.title}}
|
9
|
+
\def\Date{\VAR{vars.date}}
|
10
|
+
|
11
|
+
%- if vars.editorial is truthy and vars.watermark is truthy
|
12
|
+
\AddToHook{shipout/foreground}{
|
13
|
+
\begin{tikzpicture}[overlay, remember picture]
|
14
|
+
\node[text=gray, rotate=45, scale=8, opacity=0.3]
|
15
|
+
at (0.5\paperwidth,-0.6\paperheight) {EDITORIAL};
|
16
|
+
\end{tikzpicture}
|
17
|
+
}
|
22
18
|
%- endif
|
23
|
-
%- endfor
|
24
|
-
|
25
|
-
\def\showSourceFileName{1}
|
26
|
-
\newif\ifintentionallyblankpages % comment this out to add blank pages
|
27
|
-
|
28
|
-
\pagestyle{fancy}
|
29
|
-
\fancyhf{}
|
30
|
-
\renewcommand{\footrulewidth}{0.4pt}
|
31
|
-
|
32
|
-
%- if contest is defined
|
33
|
-
\title{\VAR{contest.title or ""}}
|
34
|
-
\author{\VAR{contest.location if contest.location is defined else ""}}
|
35
|
-
\date{\VAR{contest.date if contest.date is defined else ""}}
|
36
|
-
%- else
|
37
|
-
\title{}
|
38
|
-
\author{}
|
39
|
-
\date{}
|
40
|
-
%- endif
|
41
|
-
|
42
|
-
\makeatletter
|
43
|
-
\let\newtitle\@title
|
44
|
-
\let\newauthor\@author
|
45
|
-
\let\newdate\@date
|
46
|
-
\makeatother
|
47
|
-
|
48
|
-
\rhead{\newtitle}
|
49
|
-
\lhead{\newauthor}
|
50
|
-
\lfoot{\newdate}
|
51
|
-
\rfoot{\thepage}
|
52
19
|
|
53
20
|
\begin{document}
|
54
21
|
|
55
|
-
%- if
|
56
|
-
\
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
\item A prova tem duração de 5 horas;
|
61
|
-
\end{enumerate}
|
62
|
-
\item Sobre a entrada:
|
63
|
-
\begin{enumerate}
|
64
|
-
\item A entrada do seu programa deve ser lida da entrada padrão (standard input);
|
65
|
-
\item Quando uma linha da entrada contém vários valores, estes são separados por um único espaço em branco, a menos que explicitado o contrário no enunciado do problema;
|
66
|
-
\item Toda linha da entrada terminará com um caractere final-de-linha.
|
67
|
-
\end{enumerate}
|
68
|
-
|
69
|
-
\item Sobre a saída:
|
70
|
-
\begin{enumerate}
|
71
|
-
\item A saída de seu programa deve ser escrita na saída padrão;
|
72
|
-
\item Quando uma linha da saída contém vários valores, estes devem ser separados por um único espaço em branco, a menos que explicitado o contrário no enunciado do problema;
|
73
|
-
\item Toda linha da saída deve terminar com um caractere final-de-linha.
|
74
|
-
\end{enumerate}
|
75
|
-
|
76
|
-
\item Sobre as submissões:
|
77
|
-
\begin{enumerate}
|
78
|
-
\item Você deve submeter o código fonte das suas soluções;
|
79
|
-
\item Os comandos utilizados para compilação serão:
|
80
|
-
\begin{enumerate}
|
81
|
-
%- for language in languages:
|
82
|
-
\item \VAR{language.name | escape}: \VAR{language.command | escape}
|
83
|
-
%- endfor
|
84
|
-
\end{enumerate}
|
85
|
-
\item Para linguagem Java, o nome da classe principal do arquivo deve ser \textbf{Main}. A classe deve ser pública.
|
86
|
-
\end{enumerate}
|
87
|
-
\centering\vspace*{\fill}\textbf{Este caderno contém \VAR{problems | length} problema(s) e \pageref{LastPage} página(s)} \\
|
88
|
-
\vspace*{\fill}
|
89
|
-
\end{itemize}
|
90
|
-
\end{frontpage}
|
22
|
+
%- if vars.editorial is truthy
|
23
|
+
\InsertEditorialTitlePage
|
24
|
+
%- else
|
25
|
+
\InsertTitlePage
|
26
|
+
\input{instructions.tex}
|
91
27
|
%- endif
|
92
28
|
|
93
29
|
%- for problem in problems
|
30
|
+
\stepcounter{problemcounter}
|
94
31
|
\subimport{\VAR{problem.path | parent}/}{\VAR{problem.path | stem}}
|
95
32
|
%- endfor
|
96
33
|
|
34
|
+
\label{lastpage}
|
97
35
|
\end{document}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
\section*{General Information}
|
2
|
+
|
3
|
+
This task sheet consists of \pageref*{lastpage} pages (not counting the cover), numbered from 1 to \pageref*{lastpage}. Check if the sheet is complete.
|
4
|
+
|
5
|
+
\subsection*{Input}
|
6
|
+
|
7
|
+
\begin{itemize}
|
8
|
+
\item The input must be read from standard input.
|
9
|
+
|
10
|
+
\item All lines in the input, including the last one, end with a line break character (\texttt{\textbackslash n}).
|
11
|
+
|
12
|
+
\item When the input contains multiple space-separated values, there is exactly one whitespace character between two consecutive values on the same line.
|
13
|
+
\end{itemize}
|
14
|
+
|
15
|
+
\subsection*{Output}
|
16
|
+
|
17
|
+
\begin{itemize}
|
18
|
+
\item The output must be written to standard output.
|
19
|
+
|
20
|
+
\item The output must follow the format specified in the problem statement. The output must not contain any extra data.
|
21
|
+
|
22
|
+
\item All lines in the output, including the last one, must end with a line break character (\texttt{\textbackslash n}).
|
23
|
+
|
24
|
+
\item When a line in the output displays multiple space-separated values, there must be exactly one whitespace character between two consecutive values.
|
25
|
+
|
26
|
+
\item When an output value is a real number, use at least the number of decimal places corresponding to the precision required in the problem statement.
|
27
|
+
\end{itemize}
|
28
|
+
|
29
|
+
% \subsection*{Interactive Problems}
|
30
|
+
|
31
|
+
% The contest may contain interactive problems. In this type of problem, the input data provided to your program may not be predetermined but is instead specifically constructed for your solution. The judge writes a special program (the interactor), whose output is transferred to your solution's input, and your program's output is sent to the interactor's input. In other words, your solution and the interactor exchange data and may decide what to print based on the communication history.
|
32
|
+
|
33
|
+
% When writing a solution for an interactive problem, it is important to remember that if you print any data, it may first be stored in an internal \textit{buffer} and not immediately transferred to the interactor. To avoid this situation, you must use a special \textit{flush} operation every time you print data. These flush operations are available in the standard libraries of almost all programming languages:
|
34
|
+
|
35
|
+
% \begin{itemize}
|
36
|
+
% \item \texttt{fflush(stdout)} in \texttt{C}.
|
37
|
+
% \item \texttt{cout.flush()} in \texttt{C++}.
|
38
|
+
% \item \texttt{sys.stdout.flush()} in \texttt{Python}.
|
39
|
+
% \item \texttt{System.out.flush()} in \texttt{Java}.
|
40
|
+
% \end{itemize}
|
Binary file
|
@@ -0,0 +1,67 @@
|
|
1
|
+
---
|
2
|
+
sandbox: "stupid"
|
3
|
+
defaultCompilation:
|
4
|
+
sandbox:
|
5
|
+
maxProcesses: 1000
|
6
|
+
timeLimit: 50000 # 50 seconds
|
7
|
+
wallTimeLimit: 50000 # 50 seconds
|
8
|
+
memoryLimit: 1024 # 1gb
|
9
|
+
defaultExecution:
|
10
|
+
sandbox:
|
11
|
+
# Useful for checkers, validators, etc.
|
12
|
+
timeLimit: 50000 # 50 seconds
|
13
|
+
wallTimeLimit: 50000 # 50 seconds
|
14
|
+
memoryLimit: 1024 # 1gb
|
15
|
+
languages:
|
16
|
+
- name: "cpp"
|
17
|
+
readableName: "C++20"
|
18
|
+
extension: "cpp"
|
19
|
+
compilation:
|
20
|
+
commands: ["g++ -std=c++20 -O2 -o {executable} {compilable}"]
|
21
|
+
execution:
|
22
|
+
command: "./{executable}"
|
23
|
+
fileMapping:
|
24
|
+
compilable: "compilable.cpp"
|
25
|
+
extensions:
|
26
|
+
boca:
|
27
|
+
bocaLanguage: "cc"
|
28
|
+
- name: "c"
|
29
|
+
readableName: "C"
|
30
|
+
extension: "c"
|
31
|
+
compilation:
|
32
|
+
commands: ["gcc -std=gnu11 -O2 -lm -o {executable} {compilable}"]
|
33
|
+
execution:
|
34
|
+
command: "./{executable}"
|
35
|
+
fileMapping:
|
36
|
+
compilable: "compilable.c"
|
37
|
+
- name: "py"
|
38
|
+
readableName: "Python3"
|
39
|
+
extension: "py"
|
40
|
+
execution:
|
41
|
+
command: "python3 {executable}"
|
42
|
+
fileMapping:
|
43
|
+
executable: "executable.py"
|
44
|
+
extensions:
|
45
|
+
boca:
|
46
|
+
bocaLanguage: "py3"
|
47
|
+
- name: "java"
|
48
|
+
readableName: "Java"
|
49
|
+
extension: "java"
|
50
|
+
compilation:
|
51
|
+
commands:
|
52
|
+
- "javac -Xlint -encoding UTF-8 {compilable}"
|
53
|
+
- "jar cvf {executable} @glob:*.class"
|
54
|
+
execution:
|
55
|
+
command:
|
56
|
+
"java -Xss100m -Xmx{{memory}}m -Xms{{initialMemory}}m -cp {executable}
|
57
|
+
Main"
|
58
|
+
fileMapping:
|
59
|
+
compilable: "Main.java"
|
60
|
+
executable: "Main.jar"
|
61
|
+
extensions:
|
62
|
+
boca:
|
63
|
+
languages: ["c", "cc", "java", "py3"]
|
64
|
+
flags:
|
65
|
+
c: "-O2 -lm -static"
|
66
|
+
cc: "-std=c++20 -O2 -lm -static"
|
67
|
+
preferContestLetter: true
|
@@ -4,11 +4,15 @@ name: "default"
|
|
4
4
|
uri: "rsalesc/rbx/rbx/resources/presets/default"
|
5
5
|
problem: "problem"
|
6
6
|
contest: "contest"
|
7
|
+
env: "env.rbx.yml"
|
7
8
|
tracking:
|
8
9
|
problem:
|
10
|
+
- path: ".gitignore"
|
11
|
+
- path: "statement/icpc.sty"
|
9
12
|
- path: "statement/template.rbx.tex"
|
10
|
-
- path: "statement/olymp.sty"
|
11
13
|
contest:
|
14
|
+
- path: ".gitignore"
|
15
|
+
- path: "statement/icpc.sty"
|
12
16
|
- path: "statement/template.rbx.tex"
|
13
|
-
- path: "statement/olymp.sty"
|
14
17
|
- path: "statement/contest.rbx.tex"
|
18
|
+
symlink: true
|