Logo ryp 的博客

博客

WyOJ Datum

...
ryp
2026-01-03 17:36:34
Light away, it won't be long.
import os
import time
import subprocess
import sys
import argparse
import time
from openai import OpenAI

def fetch_generator(statement, model, maxtokens):
    APIKEY = os.environ.get('DEEPSEEK_API_KEY')
    if not APIKEY:
        raise Exception('需要设置 DEEPSEEK_API_KEY 环境变量')

    client = OpenAI(
        api_key=APIKEY,
        base_url='https://api.deepseek.com')

    start_time = time.time()
    msgs = [{ 'role': 'user', 'content':
             """
请根据以下信息学竞赛题目生成数据生成器。只输出 gen.py 代码。
要求:
1. 解析题目中的输入格式、数据范围和子任务划分
2. 创建 data/ 目录并生成所有 .in 文件
3. 数据严格符合题目约束
4. 使用合理的数据梯度,包含边界情况
5. 数据文件名一定为 'data{编号}.in',编号不含前导零
6. 没有子任务的,数据文件直接放在 data/ 下;有子任务的,为每个子任务创建 subtask{编号}/ 目录,把数据文件移动到对应的子任务目录中
7. 数据点在 10 到 20 个内
8. 务必确保你给出的数据是正确的!先列出生成器的设计思路和待满足的所有约束条件,确认无误后再生成完整代码
输出只包含可以直接运行的 gen.py 的代码,无其他内容。
题目描述:""" + statement}]
    resp = client.chat.completions.create(
            model=model,
            messages=msgs,
            stream=False,
            temperature=0.0,
            max_tokens=maxtokens)

    response = resp.choices[0].message.content
    tokens = resp.usage.total_tokens

    if response.startswith('```python'):
        response = response[9:-3]
    return (response, tokens, time.time() - start_time)

def execute(s):
    print('正在执行命令:', s)

    try:
        subprocess.run(['bash', '-c', s], check=True, timeout=40)
    except subprocess.CalledProcessError as e:
        raise Exception('命令执行错误')
    except subprocess.TimeoutExpired:
        raise Exception('命令执行超时(20s)')

def generate_in():
    # 其实应该用个沙盒比较安全,但是我懒得写了。可以最后扔到容器里头跑。
    execute('python gen.py')

def flatten_data():
    execute('find -type f | xargs -I {} mv -n {} . || true')
    execute('rmdir subtask* || true')

def run_std():
    if not os.path.exists('../std.cpp'):
        raise Exception('未找到 std.cpp')
    execute('g++ ../std.cpp -o std -Wall -Wextra -O2 -std=c++14')

    for i in os.listdir():
        if not i.endswith('.in'):
            print(f'警告:未知文件 {i}')
            continue
        out = i[:-2] + 'ans'
        execute(f'./std < {i} > {out}')
    execute('rm std')

def gen_problem_conf(time, mem):
    execute(f'python ../autoconf.py {time} {mem}')

def compress_data():
    execute('zip ../data.zip -r .')

def cleanup():
    os.chdir('..')
    execute('rm -r data/')

def pretty_size(d):
    if d < 1024:
        return f'{d}'
    if d < 1048576:
        return f'{d/1024:.2f} KB'
    return f'{d/1048576:.2f} MB'

if __name__ == '__main__':
    start_time = time.time()

    parser = argparse.ArgumentParser()
    parser.add_argument('statement', help='题面文件')
    parser.add_argument('--model', type=str, default='deepseek-reasoner', help='使用的模型(默认为 deepseek-reaonser,可以改为 deepseek-chat)')
    parser.add_argument('--maxtokens', type=int, default=50000, help='token 上限(默认为 50000)')
    parser.add_argument('--time', type=int, default=1, help='时间限制(秒,默认为 1)')
    parser.add_argument('--mem', type=int, default=256, help='空间限制(MB,默认为 256)')
    parser.add_argument('--offline', help='不生成新的 gen.py', action='store_true')
    args = parser.parse_args()

    if os.path.exists('data'):
        print('正在清空已有的 data 目录')
        execute('rm -r data')
    if os.path.exists('data.zip'):
        print('删除已存在的 data.zip')
        execute('rm data.zip')

    tokens = 0

    with open(args.statement) as f:
        if not args.offline:
            print(f'正在请求 {args.model},token 上限为 {args.maxtokens} 个')
            resp, tokens, duration = fetch_generator(f.read(), args.model, args.maxtokens)
            with open('gen.py', 'w') as fw:
                fw.write(resp)
            print(f'--- tokens: {tokens}, time cost: {duration:.6f} seconds')
        else:
            if not os.path.exists('gen.py'):
                raise Exception('离线模式下必须提供已有的 gen.py')
            print('(离线模式)')

        generate_in()
        os.chdir('data')
        gen_problem_conf(args.time, args.mem)

        # run_std 需要一个扁平的目录,也就是所有文件放在 data/ 下,而 autoconf.py 不要求这么做
        flatten_data()
        run_std()
        compress_data()
        cleanup()
        prettysize = pretty_size(os.path.getsize('data.zip'))
        print(f'已生成 data.zip({prettysize}),耗时 {(time.time() - start_time):.2f} 秒,消耗 {tokens} 个 token')

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。