浅谈online judge平台 spj [special judge] 使用 | 修改问题

article/2025/9/27 0:44:34

浅谈oj平台 spj 使用 | 修改问题

    • 首先:
      • 参数对应
      • 返回值
      • 代码提交
      • 几种spj
        • 第一种:简单的一类特判
        • 第二种:多组输入的特判
        • 第三种:需要判断特殊情况[impossible]
        • 第四种:带有[testlib.h]的spj
        • 第五种:GCPC [German Collegiate Programming Contest] 类spj
          • 单个文件的情况
          • *.h *.cpp的情况
        • 第六种:交互题的spj
        • 第七种[带有testlib.h]的另一种解决方式
        • 第八种 使用validation.h的BAPC2018(较难)

以LDUOJ为例 goto -> github
LDUOJ 平台开发者spj开发博客
不同的平台的spj使用规则可能不太一样,但是需要改动的地方不是太多

首先:

附LDUOJ之父赵京龙学长的特判使用文档地址:https://winterant.github.io/OnlineJudge/web/spj.html

参数对应

args[1] 对应数据的输入
args[2] 对应数据的答案也就是一种允许的情况 或 impossible的情况(下面会讲到)
args[3] 对应用户结果的输出,也就是需要重点关注的地方

返回值

0代表没有问题即 AC
1代表出现问题即 WA
对于有的系统来说
42代表AC,43代表WA,不同的系统可能是不一样的返回值

代码提交

和牛客平台等类似,提交的Java代码主类的类名必须是Main 否则会编译错误
就比如应该是:

public class Main{public static void main(){/**your code**/}
}

几种spj

第一种:简单的一类特判

比如下面这个比较简单的spj程序:

#include <stdio.h>
#include <math.h>
#include <cstring>
const double eps = 1e-6;
int main(int argc,char *args[])
{FILE * f_in=fopen(args[1],"r");FILE * f_out=fopen(args[2],"r");FILE * f_user=fopen(args[3],"r");fclose(f_in);fclose(f_out);fclose(f_user);return ret;
}

用文件指针的情况,我们可以直接用fscanf 进行输入输出
格式如下:

fscanf(pnt,"%d",&x);

其中pnt为想要从哪里读取的文件指针。比如要获取用户的输出,就要将pnt替换为f_user
以上方式写出来的spj可能不太严谨,建议换用新的模板,这个模板是存在于文档中:

#include<bits/stdc++.h>
using namespace std;#define AC 0
#define WA 1void jscanf(FILE *&fin, const char *format, ...) {va_list args;va_start(args, format);   /* 初始化变长参数列表 */int ret = vfscanf(fin, format, args);va_end(args);         /* 结束使用变长参数列表 */if (ret == EOF) {printf("When reading data, the program crashes because EOF is encountered in advance.\n");exit(WA);}
}bool is_whitespace(const char c) {return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}//检查用户是否存在多余输出
int read_until_eof(FILE *&fp) {char ch = fgetc(fp);while (ch != EOF && is_whitespace(ch)) {ch = fgetc(fp);}if (ch != EOF) {printf("There is redundant content in user output\n");return WA;}return AC;
}int judge(FILE *&std_in, FILE *&std_out, FILE *&user_out);int main(int argc, char *args[]) {if (argc <= 1) {printf("Please enter the path of input file, output file, and contestant output file in turn:\n");for (int i = 1; i <= 3; i++) {args[i] = new char[100];scanf("%s", args[i]);}}FILE *in = fopen(args[1], "r");   //测试输入FILE *out = fopen(args[2], "r");  //测试输出FILE *user = fopen(args[3], "r"); //用户输出if (in == NULL)printf("No such a file with path %s\n", args[1]);if (out == NULL)printf("No such a file with path %s\n", args[2]);if (user == NULL)printf("No such a file with path %s\n", args[3]);int result = AC;if (!in || !out ||!user)result = WA;if (judge(in, out, user) != AC || read_until_eof(user) != AC)result = WA;fclose(in);fclose(out);fclose(user);return result;
}
/*************************** 以上内容请勿修改!!! ***********************//*************************** 请在下面的jduge函数体内编写特判逻辑! ***********************/
int judge(FILE *&std_in, FILE *&std_out, FILE *&user_out) {/*** std_in: 标准输入文件* std_out: 标准输出文件* user_out: 用户输出文件* 1. 请务必使用jscanf(FILE*, char*, ...)函数读取数据,用法与fscanf()相同* 2. 你可以使用标准输出(printf或cout)向参赛选手展示错误原因** 以下部分是特判程序,需要出题人根据题意去判断用户的答案是否正确。*/double i, a, b;//jscanf(std_in, "%lf", &i); //由于该案例的特判不使用输入数据,故无需从std_in读取数据jscanf(std_out, "%lf", &a);//读取标准答案jscanf(user_out, "%lf", &b);//读取参赛选手输出的答案if (fabs(a - b) > 1e-6) {printf("Your result is beyond the scope of the answer! \n");printf("The absolute difference between your result and the standard answer is %.9f\n", fabs(a - b));return WA;}printf("Yes\n"); //这句可以不写,仅提示选手通过了一组测试数据return AC;
}

第二种:多组输入的特判

示例:UVA10886
在这里插入图片描述
对应的spj程序应该是:

#include <stdio.h>
#include <math.h>
const double eps = 1e-4;
int main(int argc,char *args[])///主函数
{FILE * f_in=fopen(args[1],"r");///测试输入FILE * f_out=fopen(args[2],"r");///测试输出FILE * f_user=fopen(args[3],"r");///用户输出int ret=0;///返回值int T;double a,x;char cas[100],num[100];fscanf(f_in,"%d",&T);///从输入中读取数据组数Twhile(T--){fscanf(f_out,"%s %s %lf",&cas,&num,&a);fscanf(f_user,"%s %s %lf",&cas,&num,&x);if(fabs(a-x)>eps)ret = 1;///Wrong Answer}fclose(f_in);fclose(f_out);fclose(f_user);return ret;
}

第三种:需要判断特殊情况[impossible]

在这里插入图片描述
则对应的spj就应该为:

#include <stdio.h>
#include <math.h>
#include <cstring>
const double eps = 1e-6;
int main(int argc,char *args[])
{FILE * f_in=fopen(args[1],"r");FILE * f_out=fopen(args[2],"r");FILE * f_user=fopen(args[3],"r");int ret = 0;double a,x;char std[100],usr[100];while(fscanf(f_out,"%s",std) == 1 && fscanf(f_user,"%s",usr) == 1){if(strcmp(std,"IMPOSSIBLE") && !strcmp(usr,"IMPOSSIBLE")) {ret = 1;return ret;}if(strcmp(usr,"IMPOSSIBLE") && !strcmp(std,"IMPOSSIBLE")){ret = 1;return ret;}double sstd = atof(std);double uusr = atof(usr);if(fabs(sstd - uusr) > eps) {ret = 1;return ret;}}fclose(f_in);fclose(f_out);fclose(f_user);return ret;
}

第四种:带有[testlib.h]的spj

一般情况下,这种题目的spj都是比较规范的,而且testlib.h是在Github上进行开源的
该头文件的发明者应该是Codeforces的管理员 MikeMirzayanov
只需要将上述中的args[]对应好就没有太大问题
2021-09-16更新
在处理的过程当中,笔者发现大部分的testlib.h类的spj与lduoj是匹配的
所以说在处理的时候如果发现spj编译报错,那么就说明用到的checker.cpp和testlib.h的版本不对应,应该参考附带的testlib.h,然后拼接在一起
在这里插入图片描述
如果发现更改spj之后还不通过std代码,首先可以试试所有的语言的标程,如果还是不通过,可以确定是spj的问题,这里就需要对spj统一换成比较朴实的spj,具体什么格式可以参考文章首部的oj开发者提供的spj使用规范
需要重新实现一下使用到的testlib.h里面的函数方法即可

第五种:GCPC [German Collegiate Programming Contest] 类spj

单个文件的情况

这种情况比较简单
以GCPC2019 Keeping the Dogs Out为例:
在这里插入图片描述
打开可以看到:

#include <fstream>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>#include <cassert>typedef long long ll;using std::cin;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::string;
using std::vector;constexpr int CORRECT = 42;///修改
constexpr int INCORRECT = 43;///修改int main(int argc, char* argv[])
{assert(argc == 4);ifstream input(argv[1]);ifstream answer(argv[2]);ofstream debug_output(argv[3] + string("/judgemessage.txt"));///修改string s1, s2;answer >> s1;cin >> s2;if (s1 != s2 && (s1 == "impossible" || s2 == "impossible")) {debug_output << "Expected: " << s1 << ", got: " << s2 << endl;///被迫对应修改return INCORRECT;}if (s1 != "impossible") {ll x, y;std::stringstream first_token(s2);if (!(first_token >> x) || !(cin >> y)) {debug_output << "Too little output" << endl;///被迫对应修改return INCORRECT;}if (!cin || x <= 0 || y <= 0) {debug_output << "Presentation Error" << endl;///被迫对应修改return INCORRECT;}if (std::numeric_limits<ll>::max() / x < y) {debug_output << "Area too large." << endl;///被迫对应修改return INCORRECT;}ll n;input >> n;vector<ll> cnt(n + 1);for (ll& i: cnt) input >> i;ll current_area = 0;for (int k = n; k >= 0; --k) {ll border_length = 1ll << k;current_area += border_length * border_length * cnt[k];ll a = (x / border_length) * border_length;ll b = (y / border_length) * border_length;if (a * b < current_area) {debug_output << "Incorrect dimensions, cannot fit all squares of size " << border_length << " and larger." << endl;///被迫对应修改return INCORRECT;}}if (current_area != x * y) {debug_output << "Area is " << x * y << ", should be " << current_area << "." << endl;///被迫对应修改return INCORRECT;}}char c;if (cin >> c) {debug_output << "Too much output." << endl;///被迫对应修改return INCORRECT;}return CORRECT;
}

改过之后的spj应该是这样子的:
值得一提的是,这里的输入并不是通过文件指针,而是通过流的方式读写文件
而且GCPC比赛平台的argc[3] 应该是将结果反馈给平台的一个参数

#include <fstream>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>#include <cassert>typedef long long ll;using std::cin;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::string;
using std::vector;constexpr int CORRECT = 0;
constexpr int INCORRECT = 1;int main(int argc, char* argv[])
{
//    assert(argc == 4);ifstream input(argv[1]);ifstream answer(argv[2]);ifstream user(argv[3]);
//    ofstream debug_output(argv[3] + string("/judgemessage.txt"));string s1, s2;answer >> s1;user >> s2;if (s1 != s2 && (s1 == "impossible" || s2 == "impossible")) {return INCORRECT;}if (s1 != "impossible") {ll x, y;std::stringstream first_token(s2);if (!(first_token >> x) || !(user >> y)) {return INCORRECT;}if (!user || x <= 0 || y <= 0) {return INCORRECT;}if (std::numeric_limits<ll>::max() / x < y) {return INCORRECT;}ll n;input >> n;vector<ll> cnt(n + 1);for (ll& i: cnt) input >> i;ll current_area = 0;for (int k = n; k >= 0; --k) {ll border_length = 1ll << k;current_area += border_length * border_length * cnt[k];ll a = (x / border_length) * border_length;ll b = (y / border_length) * border_length;if (a * b < current_area) {return INCORRECT;}}if (current_area != x * y) {return INCORRECT;}}char c;if (user >> c) {return INCORRECT;}return CORRECT;
}
*.h *.cpp的情况

以GCPC 2019 Historical Maths为例:
在这里插入图片描述
我们只需要将两个文件合并在一起就好.h文件放在上面,.cpp文件放在下面
如果遇见了某结构体或者是类里面的某个共有或私有函数没有生命的情况,八成加上using namespace std 可以解决

以这个题为例,合并这些文件之后的spj为:

#include <bits/stdc++.h>
/* Utility functions for writing output validators for the Kattis* problem format.** The primary functions and variables available are the following.* In many cases, the only functions needed are "init_io",* "wrong_answer", and "accept".** - init_io(argc, argv):*        initialization** - judge_in, judge_ans, author_out:*        std::istream objects for judge input file, judge answer*        file, and submission output file.** - accept():*        exit and give Accepted!** - accept_with_score(double score):*        exit with Accepted and give a score (for scoring problems)** - judge_message(std::string msg, ...):*        printf-style function for emitting a judge message (a*        message that gets displayed to a privileged user with access*        to secret data etc).** - wrong_answer(std::string msg, ...):*        printf-style function for exitting and giving Wrong Answer,*        and emitting a judge message (which would typically explain*        the cause of the Wrong Answer)** - judge_error(std::string msg, ...):*        printf-style function for exitting and giving Judge Error,*        and emitting a judge message (which would typically explain*        the cause of the Judge Error)** - author_message(std::string msg, ...):*        printf-style function for emitting an author message (a*        message that gets displayed to the author of the*        submission).  (Use with caution, and be careful not to let*        it leak information!)**/#include <sys/stat.h>
#include <cassert>
#include <cstdarg>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>typedef void (*feedback_function)(const std::string &, ...);const int EXITCODE_AC = 42;///注释 / 修改
const int EXITCODE_WA = 43;///注释 / 修改
const std::string FILENAME_AUTHOR_MESSAGE = "teammessage.txt";
const std::string FILENAME_JUDGE_MESSAGE = "judgemessage.txt";
const std::string FILENAME_JUDGE_ERROR = "judgeerror.txt";
const std::string FILENAME_SCORE = "score.txt";#define USAGE "%s: judge_in judge_ans feedback_dir < author_out\n"std::ifstream judge_in, judge_ans;
std::istream author_out(std::cin.rdbuf());///修改char *feedbackdir = NULL;void vreport_feedback(const std::string &category,const std::string &msg,va_list pvar) {std::ostringstream fname;if (feedbackdir)fname << feedbackdir << '/';fname << category;FILE *f = fopen(fname.str().c_str(), "a");assert(f);vfprintf(f, msg.c_str(), pvar);fclose(f);
}void report_feedback(const std::string &category, const std::string &msg, ...) {va_list pvar;va_start(pvar, msg);vreport_feedback(category, msg, pvar);
}void author_message(const std::string &msg, ...) {va_list pvar;va_start(pvar, msg);vreport_feedback(FILENAME_AUTHOR_MESSAGE, msg, pvar);
}void judge_message(const std::string &msg, ...) {va_list pvar;va_start(pvar, msg);vreport_feedback(FILENAME_JUDGE_MESSAGE, msg, pvar);
}void wrong_answer(const std::string &msg, ...) {va_list pvar;///注释 / 修改va_start(pvar, msg);vreport_feedback(FILENAME_JUDGE_MESSAGE, msg, pvar);exit(EXITCODE_WA);
}void judge_error(const std::string &msg, ...) {va_list pvar;///注释 / 修改va_start(pvar, msg);vreport_feedback(FILENAME_JUDGE_ERROR, msg, pvar);assert(0);
}void accept() {exit(EXITCODE_AC);
}void accept_with_score(double scorevalue) {report_feedback(FILENAME_SCORE, "%.9le", scorevalue);exit(EXITCODE_AC);
}bool is_directory(const char *path) {struct stat entry;return stat(path, &entry) == 0 && S_ISDIR(entry.st_mode);
}void init_io(int argc, char **argv) {if(argc < 4) {///注释 / 修改fprintf(stderr, USAGE, argv[0]);///注释 / 修改judge_error("Usage: %s judgein judgeans feedbackdir [opts] < userout", argv[0]);///注释 / 修改}///注释 / 修改
///注释 / 修改// Set up feedbackdir first, as that allows us to produce feedback///注释 / 修改// files for errors in the other parameters.///注释 / 修改if (!is_directory(argv[3])) {///注释 / 修改judge_error("%s: %s is not a directory\n", argv[0], argv[3]);///注释 / 修改}///注释 / 修改feedbackdir = argv[3];///注释 / 修改judge_in.open(argv[1], std::ios_base::in);if (judge_in.fail()) {judge_error("%s: failed to open %s\n", argv[0], argv[1]);}judge_ans.open(argv[2], std::ios_base::in);if (judge_ans.fail()) {judge_error("%s: failed to open %s\n", argv[0], argv[2]);}author_out.rdbuf(std::cin.rdbuf());///注释 / 修改
}using namespace std;
using ll = long long;
using vl = vector<ll>;
#define sz(c) ll((c).size())
#define FOR(i,a,b) for(ll i = (a); i < (b); i++)
#define FORD(i,a,b) for(ll i = ll(b) - 1; i >= (a); i--)const ll MAX_BASE = (2LL << 60) + 1;ll check_and_parse_author(const string& to_parse) {//first pass; check for invalid characterif(sz(to_parse) == 0) wrong_answer("Submission provided empty string to parse.\n");if(to_parse[0] == '+' && sz(to_parse) == 1) wrong_answer("Answer is not a number.\n");if(to_parse[0] != '+' && (to_parse[0] < '0' || '9' < to_parse[0])) wrong_answer("Answer contains invalid character.\n");FOR(i,1,sz(to_parse)) if(to_parse[i] < '0' || '9' < to_parse[i]) wrong_answer("Answer contains invalid character.\n");//second pass; calculate answer basell base = 0;if(to_parse[0] != '+') base = to_parse[0] - '0';FOR(i,1,sz(to_parse)) {// avoid overflowif(MAX_BASE / 10 < base) return MAX_BASE;base = base*10 + (to_parse[i] - '0');}return base;
}
void multiply(vl &a, vl &b, vl &res, ll base) {res.assign(sz(res), 0);FOR(i,0,sz(a)) {FOR(j,0,sz(b)) {res[i + j] += a[i] * b[j];res[i + j + 1] += res[i + j] / base;res[i + j] %= base;}}FOR(i,0,sz(res) - 1) {res[i + 1] += res[i] / base;res[i] %= base;}
}ll compare(vl &a, vl &b) {if(sz(a) < sz(b)) {FOR(i,sz(a),sz(b)) if(b[i] != 0) return -1;}if(sz(a) > sz(b)) {FOR(i,sz(b), sz(a)) if(a[i] != 0) return 1;}FORD(i,0,min(sz(a),sz(b))) {if(a[i] - b[i] != 0) return a[i] - b[i];}return 0;
}int main(int argc, char **argv) {init_io(argc,argv);///注释 / 修改这个函数string a_ans, j_ans;char foo;judge_ans >> j_ans;if(!( author_out >> a_ans)) wrong_answer("Less output than expected.\n");if(author_out >> foo) wrong_answer("More output than expected.\n");transform(a_ans.begin(), a_ans.end(), a_ans.begin(), ::tolower);//quick acceptif(a_ans == j_ans) accept();if(a_ans == "impossible") wrong_answer("Submission claims impossible, judge has answer.\n");ll base = check_and_parse_author(a_ans);if(base < 2) wrong_answer("Invalid base.\n");bool differs = false;if(j_ans == "impossible") differs = true;ll tmp, maxdigit = 1;judge_in >> tmp;vl a(tmp);FORD(i, 0, tmp) {judge_in >> a[i]; maxdigit = max(maxdigit, a[i]);}judge_in >> tmp;vl b(tmp);FORD(i, 0, tmp){ judge_in >> b[i]; maxdigit = max(maxdigit, b[i]);}judge_in >> tmp;vl prod(tmp);FORD(i, 0, tmp){ judge_in >> prod[i]; maxdigit = max(maxdigit, prod[i]);}vl res(sz(a) + sz(b) + 1);if(base < maxdigit + 1) wrong_answer("Base not greater than all occuring digits.\n");multiply(a,b,res,base);ll cmp = compare(prod, res);if(cmp == 0) {if(differs)judge_error("Judge answer is 'impossible' but submission gave valid answer.\n");accept();}wrong_answer("Invalid base.\n");
}

由于平台不同的原因,在函数含有某行对文件写操作的代码会出现问题,所以要注释掉,还要将返回的状态码改成0 1,而不是使用42 43
注意有些头文件在Windows平台下并不能使用,会报出编译错误,但是在Linux平台下却是可以的,提交spj之后会编译成功
需要修改的地方已在上面的代码中加入了批注,然后,修改之后应该是:

#include <bits/stdc++.h>
#include <sys/stat.h>
#include <cassert>
#include <cstdarg>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>typedef void (*feedback_function)(const std::string &, ...);const int EXITCODE_AC = 0;
const int EXITCODE_WA = 1;
const std::string FILENAME_AUTHOR_MESSAGE = "teammessage.txt";
const std::string FILENAME_JUDGE_MESSAGE = "judgemessage.txt";
const std::string FILENAME_JUDGE_ERROR = "judgeerror.txt";
const std::string FILENAME_SCORE = "score.txt";#define USAGE "%s: judge_in judge_ans feedback_dir < author_out\n"std::ifstream judge_in, judge_ans;
std::ifstream author_out;char *feedbackdir = NULL;void vreport_feedback(const std::string &category,const std::string &msg,va_list pvar) {std::ostringstream fname;if (feedbackdir)fname << feedbackdir << '/';fname << category;FILE *f = fopen(fname.str().c_str(), "a");assert(f);vfprintf(f, msg.c_str(), pvar);fclose(f);
}void report_feedback(const std::string &category, const std::string &msg, ...) {va_list pvar;va_start(pvar, msg);vreport_feedback(category, msg, pvar);
}void author_message(const std::string &msg, ...) {va_list pvar;va_start(pvar, msg);vreport_feedback(FILENAME_AUTHOR_MESSAGE, msg, pvar);
}void judge_message(const std::string &msg, ...) {va_list pvar;va_start(pvar, msg);vreport_feedback(FILENAME_JUDGE_MESSAGE, msg, pvar);
}void wrong_answer(const std::string &msg, ...) {
//	va_list pvar;
//	va_start(pvar, msg);
//	vreport_feedback(FILENAME_JUDGE_MESSAGE, msg, pvar);exit(EXITCODE_WA);
}void judge_error(const std::string &msg, ...) {
//	va_list pvar;
//	va_start(pvar, msg);
//	vreport_feedback(FILENAME_JUDGE_ERROR, msg, pvar);assert(0);
}void accept() {exit(EXITCODE_AC);
}void accept_with_score(double scorevalue) {
//	report_feedback(FILENAME_SCORE, "%.9le", scorevalue);exit(EXITCODE_AC);
}bool is_directory(const char *path) {struct stat entry;return stat(path, &entry) == 0 && S_ISDIR(entry.st_mode);
}void init_io(int argc, char **argv) {
//	if(argc < 4) {
//		fprintf(stderr, USAGE, argv[0]);
//		judge_error("Usage: %s judgein judgeans feedbackdir [opts] < userout", argv[0]);
//	}
//
//	// Set up feedbackdir first, as that allows us to produce feedback
//	// files for errors in the other parameters.
//	if (!is_directory(argv[3])) {
//		judge_error("%s: %s is not a directory\n", argv[0], argv[3]);
//	}
//	feedbackdir = argv[3];judge_in.open(argv[1], std::ios_base::in);if (judge_in.fail()) {judge_error("%s: failed to open %s\n", argv[0], argv[1]);}judge_ans.open(argv[2], std::ios_base::in);if (judge_ans.fail()) {judge_error("%s: failed to open %s\n", argv[0], argv[2]);}author_out.open(argv[3], std::ios_base::in);if (author_out.fail()) {judge_error("%s: failed to open %s\n", argv[0], argv[3]);}
}using namespace std;
using ll = long long;
using vl = vector<ll>;
#define sz(c) ll((c).size())
#define FOR(i,a,b) for(ll i = (a); i < (b); i++)
#define FORD(i,a,b) for(ll i = ll(b) - 1; i >= (a); i--)const ll MAX_BASE = (2LL << 60) + 1;ll check_and_parse_author(const string& to_parse) {//first pass; check for invalid characterif(sz(to_parse) == 0) wrong_answer("Submission provided empty string to parse.\n");if(to_parse[0] == '+' && sz(to_parse) == 1) wrong_answer("Answer is not a number.\n");if(to_parse[0] != '+' && (to_parse[0] < '0' || '9' < to_parse[0])) wrong_answer("Answer contains invalid character.\n");FOR(i,1,sz(to_parse)) if(to_parse[i] < '0' || '9' < to_parse[i]) wrong_answer("Answer contains invalid character.\n");//second pass; calculate answer basell base = 0;if(to_parse[0] != '+') base = to_parse[0] - '0';FOR(i,1,sz(to_parse)) {// avoid overflowif(MAX_BASE / 10 < base) return MAX_BASE;base = base*10 + (to_parse[i] - '0');}return base;
}
void multiply(vl &a, vl &b, vl &res, ll base) {res.assign(sz(res), 0);FOR(i,0,sz(a)) {FOR(j,0,sz(b)) {res[i + j] += a[i] * b[j];res[i + j + 1] += res[i + j] / base;res[i + j] %= base;}}FOR(i,0,sz(res) - 1) {res[i + 1] += res[i] / base;res[i] %= base;}
}ll compare(vl &a, vl &b) {if(sz(a) < sz(b)) {FOR(i,sz(a),sz(b)) if(b[i] != 0) return -1;}if(sz(a) > sz(b)) {FOR(i,sz(b), sz(a)) if(a[i] != 0) return 1;}FORD(i,0,min(sz(a),sz(b))) {if(a[i] - b[i] != 0) return a[i] - b[i];}return 0;
}int main(int argc, char **argv) {init_io(argc,argv);string a_ans, j_ans;char foo;judge_ans >> j_ans;if(!( author_out >> a_ans)) wrong_answer("Less output than expected.\n");if(author_out >> foo) wrong_answer("More output than expected.\n");transform(a_ans.begin(), a_ans.end(), a_ans.begin(), ::tolower);//quick acceptif(a_ans == j_ans) accept();if(a_ans == "impossible") wrong_answer("Submission claims impossible, judge has answer.\n");ll base = check_and_parse_author(a_ans);if(base < 2) wrong_answer("Invalid base.\n");bool differs = false;if(j_ans == "impossible") differs = true;ll tmp, maxdigit = 1;judge_in >> tmp;vl a(tmp);FORD(i, 0, tmp) {judge_in >> a[i];maxdigit = max(maxdigit, a[i]);}judge_in >> tmp;vl b(tmp);FORD(i, 0, tmp) {judge_in >> b[i];maxdigit = max(maxdigit, b[i]);}judge_in >> tmp;vl prod(tmp);FORD(i, 0, tmp) {judge_in >> prod[i];maxdigit = max(maxdigit, prod[i]);}vl res(sz(a) + sz(b) + 1);if(base < maxdigit + 1) wrong_answer("Base not greater than all occuring digits.\n");multiply(a,b,res,base);ll cmp = compare(prod, res);if(cmp == 0) {if(differs)judge_error("Judge answer is 'impossible' but submission gave valid answer.\n");accept();}wrong_answer("Invalid base.\n");
}

第六种:交互题的spj

本平台暂不支持交互题,所以题库里的交互题目前没有进行处理通过
可以参考洛谷的交互题spj对应写法

第七种[带有testlib.h]的另一种解决方式

…遇见后后续更新
2021-10-21更新
将以下文件入口对应
inf->标准输入 argv[1]
ouf->用户输出 argv[3]
ans->答案结果 argv[2]

void registerTestlibCmd(int argc, char* argv[]) {__testlib_ensuresPreconditions();testlibMode = _checker;__testlib_set_binary(stdin);if (argc > 1 && !strcmp("--help", argv[1]))__testlib_help();// if (argc < 4 || argc > 6)// {//     quit(_fail, std::string("Program must be run with the following arguments: ") +//         std::string("<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]") +//         "\nUse \"--help\" to get help information");// }appesMode = false;//	if (argc == 3) {///改 
//		resultName = "";
//		appesMode = false;
//	}
//
//	if (argc == 4) {
//		resultName = make_new_file_in_a_dir(argv[3]);
//		appesMode = false;
//	}///改 // if (argc == 6)// {//     if (strcmp("-APPES", argv[5]) && strcmp("-appes", argv[5]))//     {//         quit(_fail, std::string("Program must be run with the following arguments: ") +//                     "<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]");//     }//     else//     {//         resultName = argv[4];//         appesMode = true;//     }// }inf.init(argv[1], _input);ouf.init(argv[3], _output);ans.init(argv[2], _answer);/// 改 
}void registerTestlib(int argc, ...) {if (argc  < 3 || argc > 5)quit(_fail, std::string("Program must be run with the following arguments: ") +"<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]");char** argv = new char*[argc + 1];va_list ap;va_start(ap, argc);argv[0] = NULL;for (int i = 0; i < argc; i++) {argv[i + 1] = va_arg(ap, char*);}va_end(ap);registerTestlibCmd(argc + 1, argv);delete[] argv;
}

第八种 使用validation.h的BAPC2018(较难)

首先站是原始的BAPC后台validation.h文件:

// A header library to safely parse team input.
// It does not support floating points or big integers.// The easiest way to use this is to symlink it from a validator directory,
// so that it will be picked up when creating a contest zip.// The default checking behaviour is lenient for both white space and case.
// When validating .in and .ans files, the case_sensitve and space_change_sensitive flags should be
// passed. When validating team output, the flags in problem.yaml should be used.#include <algorithm>
#include <stdexcept>
#include <fstream>
#include <iostream>
#include <limits>
using namespace std;const string case_sensitive_flag         = "case_sensitive";
const string space_change_sensitive_flag = "space_change_sensitive";class Validator {const int ret_AC = 42, ret_WA = 43;bool case_sensitive;bool ws;public:Validator(int argc, char **argv, istream &in = std::cin) : in(in) {for(int i = 0; i < argc; ++i) {if(argv[i] == case_sensitive_flag) case_sensitive = true;if(argv[i] == space_change_sensitive_flag) ws = true;}if(ws) in >> noskipws;}// No copying, no moving.Validator(const Validator &) = delete;Validator(Validator &&)      = delete;// At the end of the scope, check whether the EOF has been reached.// If so, return AC. Otherwise, return WA.~Validator() {eof();AC();}void space() {if(ws) {char c;in >> c;if(c != ' ') expected("space", string("\"") + c + "\"");}// cerr << "read space!\n";}void newline() {if(ws) {char c;in >> c;if(c != '\n') expected("newline", string("\"") + c + "\"");}// cerr << "read newline!\n";}// Just read a string.string read_string() { return read_string_impl(); }// Read a string and make sure it equals `expected`.string read_string(string expected) { return read_string_impl(expected); }// Read an arbitrary string of a given length.string read_string(size_t min, size_t max) {string s = read_string();if(s.size() < min || s.size() > max)expected("String of length between " + to_string(min) + " and " + to_string(max), s);return s;}// Read the string t.void test_string(string t) {string s = read_string();if(case_sensitive) {if(s != t) expected(t, s);} else {if(lowercase(s) != lowercase(t)) expected(t, s);}}// Read a long long.long long read_long_long() {string s = read_string_impl("", "integer");long long v;try {size_t chars_processed = 0;v                      = stoll(s, &chars_processed);if(chars_processed != s.size())WA("Parsing " + s + " as long long failed! Did not process all characters");} catch(const out_of_range &e) {WA("Number " + s + " does not fit in a long long!");} catch(const invalid_argument &e) { WA("Parsing " + s + " as long long failed!"); }return v;}// Read a long long within a given range.long long read_long_long(long long low, long long high) {auto v = read_long_long();if(low <= v && v <= high) return v;expected("integer between " + to_string(low) + " and " + to_string(high), to_string(v));}int read_int() {return read_long_long(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());}int read_int(int low, int high) {int v = read_long_long(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());if(low <= v && v <= high) return v;expected("integer between " + to_string(low) + " and " + to_string(high), to_string(v));}// Read a long double.long double read_long_double() {string s = read_string_impl("", "integer");long double v;try {size_t chars_processed;v = stold(s, &chars_processed);if(chars_processed != s.size())WA("Parsing ", s, " as long double failed! Did not process all characters.");} catch(const out_of_range &e) {WA("Number " + s + " does not fit in a long double!");} catch(const invalid_argument &e) { WA("Parsing " + s + " as long double failed!"); }return v;}// Check the next character.bool peek(char c) {if(!ws) in >> ::ws;return in.peek() == char_traits<char>::to_int_type(c);}// Return WRONG ANSWER verdict.[[noreturn]] void expected(string exp = "", string s = "") {if(s.size())cout << "Expected " << exp << ", found " << s << endl;else if(exp.size())cout << exp << endl;exit(ret_WA);}template <typename T>[[noreturn]] void WA(T t) {cout << t << endl;exit(ret_WA);}template <typename T, typename... Ts>[[noreturn]] void WA(T t, Ts... ts) {cout << t;WA(ts...);}template <typename... Ts>void assert(bool b, Ts... ts) {if(!b) WA(ts...);}private:// Read an arbitrary string.// expected: if not "", string must equal this.// wanted: on failure, print "expected <wanted>, got ..."string read_string_impl(string expected_string = "", string wanted = "string") {if(ws) {char next = in.peek();if(isspace(next)) expected(wanted, "whitespace");}string s;if(in >> s) {if(!case_sensitive) {s               = lowercase(s);expected_string = lowercase(expected_string);}if(!expected_string.empty() && s != expected_string)WA("Expected string \"expected\", but found ", s);return s;}expected(wanted, "nothing");}// Return ACCEPTED verdict.[[noreturn]] void AC() { exit(ret_AC); }void eof() {if(in.eof()) return;// Sometimes EOF hasn't been triggered yet.if(!ws) in >> ::ws;char c = in.get();if(c == char_traits<char>::eof()) return;expected("EOF", string("\"") + char(c) + "\"");}// Convert a string to lowercase is matching is not case sensitive.string &lowercase(string &s) {if(!case_sensitive) return s;transform(s.begin(), s.end(), s.begin(), ::tolower);return s;}istream &in;
};

我们尤其需要注意公有成员方法:

Validator(int argc, char **argv, istream &in = std::cin) : in(in) {for(int i = 0; i < argc; ++i) {if(argv[i] == case_sensitive_flag) case_sensitive = true;if(argv[i] == space_change_sensitive_flag) ws = true;}if(ws) in >> noskipws;}

main中的前几行代码:

// Set up the input and answer streams.std::ifstream in(argv[1]);std::ifstream ans(argv[2]);

因为本平台都是使用文件的形式进行判断所提交的代码,这里可以用流的形式进行操作,将42、43改成对应的0、1然后将main中添加如下代码:

// Set up the input and answer streams.std::ifstream in(argv[1]);std::ifstream ans(argv[2]);std::ifstream user(argv[3]);Validator out(argc, argv, user);// 以下代码为输入

然后将公有成员构造方法改成:

Validator(int argc, char **argv, std::ifstream &in) : in(in) {for(int i = 0; i < argc; ++i) {if(argv[i] == case_sensitive_flag) case_sensitive = true;if(argv[i] == space_change_sensitive_flag) ws = true;}if(ws) in >> noskipws;
}

即可完美解决


http://chatgpt.dhexx.cn/article/5vQNP9I0.shtml

相关文章

HUSTOJ SPJ 示例

什么是 SPJ SPJ 是 Special Judge 的意思。 什么时候使用 SPJ 当题目答案不止一个的时候&#xff0c;我们就必须使用 SPJ。 如何使用 SPJ 题目中打开 SPJ 首先&#xff0c;我们需要在出题的时候&#xff0c;增加 SPJ 选项&#xff0c;如下图所示。 题目保存后&#xff0…

《数据库原理与运用》上机实验之SPJ

《数据库原理与运用》上机实验之SPJ 前言一、关系模式二、使用SQL语句创建、修改基本表1.对基本表字段名的增加2.对基本表字段名的增加3.索引 二、使用SQL语句对数据库表的单表查询1.对指定列的查询2.对表达式计算和改变表达方式的查询3.消除重复行的查询4.WHERE条件查询5.分组…

SPJ数据库查询

起始 SQL语句建表 建表 后续图示为在SQL Server Management Studio中快捷创建的&#xff0c;并不是代码创建的。 CREATE TABLE S ( SNO CHAR(2) UNIQUE, SNAME CHAR(6), STATUS CHAR(2), CITY CHAR(4));CREATE TABLE J (JNO CHAR(2), JNAME CHAR(8), CITY CHAR(4) ); CREATE …

二 DeepinV20版本安装

安装 https://www.deepin.org/zh/download/ 准备工作&#xff1a;一个U盘&#xff0c;4G就够&#xff1b;镜像包&#xff1b;老毛桃或是官网提供的启动工具。 分区规划&#xff1a;至少3个区&#xff0c; 一个挂 / &#xff08;建议至少10G&#xff09;, SWAP分区&#xff08…

Windows10+deepin双系统安装(选用意义,安装教程)

1.为什么选用deepin 为什么要选用deepin&#xff0c;想必能看到该篇文章&#xff0c;肯定知道deepin是linux系统&#xff0c;而linux系统的发行版众多&#xff0c;至于具体那些&#xff0c;又有什么区别&#xff0c;请读者参考https://blog.csdn.net/bernin/article/details/83…

Deepin安装NVIDIA显卡驱动

显卡驱动可以通过官方库安装&#xff0c;本文使用官方NVIDIA 驱动手动安装。 时间&#xff1a;2020.8 系统版本&#xff1a;Deepin v20 beta Nvidia驱动安装 1 下载驱动 进入NVIDIA官网下载Linux驱动&#xff1a;NVIDIA官网驱动下载 找到对应驱动后下载&#xff0c;记住下载位…

【系统 win10 deepin】双系统安装(win10和deepin双系统)

概述 所有的事情都源自于一只蝙蝠&#xff0c;在这个无聊且漫长的寒假&#xff0c;终于能够实现躺在家里也能为国家做出贡献的时候了。 既然闲着也是闲着&#xff0c;那为何不折腾一下自己的电脑呢。 相信很多猿在虚拟机里已经体验过linux系统&#xff0c;那么怎么在实体机上怎…

Deepin重装Win10

Deepin重装Win10 分享荣耀magicbook 8256 全盘安装deepin后&#xff0c;重装win10之旅。 如有需要请务必先看完再做&#xff01;&#xff01;&#xff01;会清除电脑硬盘上的全部数据&#xff01;&#xff01;&#xff01;请自行备份&#xff01;&#xff01; 重装win10系统我…

【Deepin】 Deepin 系统安装教程

安装过程 准备准备足够的磁盘空间下载格式化制作启动盘 安装设置U盘启动项根据引导安装新建分区 设置 记录一下第N次安装Deepin系统的过程。 准备 准备足够的磁盘空间 deepin用于生活日常的话&#xff0c;不需要太大的空间。我准备了40G左右的空间&#xff08;很小&#xff0…

国产操作系统Deepin的安装

一、简介 武汉深之度科技有限公司&#xff08;以下简称深度科技&#xff09;成立于 2011 年&#xff0c;是专注基于 Linux 的国产操作系统研发与服务的商业公司。 作为国内顶尖的操作系统研发团队&#xff0c;深度科技以提供安全可靠、美观易用的国产操作系统与开源解决方案为…

国产操作系统之深度deepin安装

一、深度deepin简介 Deepin(原名Linux Deepin)致力于为全球用户提供美观易用&#xff0c;安全可靠的Linux发行版。deepin项目于2008年发起&#xff0c;并在2009年发布了以linux deepin为名称的第一个版本。2014年4月更名为Deepin&#xff0c;在中国常被称为“深度操作系统“。深…

Deepin 20版 安装教程(Vmware)

最近一直关注着一个国产系统的动态&#xff0c;至今已经更新到20版&#xff0c;界面优美&#xff0c;体验绝佳&#xff0c;舒适度绝对不比Mac本差&#xff0c;基于Linux内核开发自研的国产系统&#xff0c;真的是细微之处&#xff0c;体验不凡&#xff01;欢迎试水。 软件的生态…

如何安装 Deepin 20.1深度操作系统(图文) ?

Deepin 深度操作系统是一个用户友好的基于 Debian 的 Linux 发行版。它是一个免费和开源的操作系统&#xff0c;主要用于桌面级别。最近&#xff0c;Deepin 20.1 的稳定版本已经发布。Deepin 20.1 附带了稳定的内核版本 5.4 和 Debian 10.6 包存储库。 系统要求 More than 2 …

Windows+Deepin双系统的安装(win11+deepin20.7.1)

WindowsDeepin双系统的安装&#xff08;win11deepin20.7.1&#xff09; 目录 [Win11deepin20的安装方法](https://blog.csdn.net/m0_53397118/article/details/121883445#%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0Win11%2Bdeepin20%E7%9A%84%E5%AE%89%E8%A3%85%E6%96%…

window+deepin双系统安装

说明 参考教程&#xff1a;https://baijiahao.baidu.com/s?id1662960328855347503 特别注意&#xff0c;最好用最新的PE工具&#xff0c;我用的 微PE。因为我弄过一次全盘安装&#xff0c;导致整个硬盘在PE工具中的diskgenius无法识别&#xff0c;最终为U盘安装最新版PE工具后…

win10下安装deepin双系统教程

1、右键电脑—>管理—>磁盘管理&#xff0c;选择空闲容量多的磁盘压缩50G空间。 2、登录网址下载镜像和U盘制作工具&#xff08;启动盘制作不懂自行百度&#xff09;。 3、U盘插入电脑重新启动&#xff0c;按F10&#xff08;每个电脑品牌不一样&#xff0c;可百度&#x…

深度操作系统deepin下载与安装教程-系统安装

前往深度社区&#xff08;deepin.org&#xff09;&#xff0c;下载deepin最新的镜像文件 下载Ventoy启动盘制作工具 插入U盘后安装Ventoy制作多系统启动U盘 安装完成后将deepin镜像文件拷贝到Ventoy多系统启动U盘 插入用Ventoy制作的deepin启动盘 按电源开机键之后狂按F12&…

Linux(Deepin)如何安装NVIDIA显卡驱动(deepin-Linux)

Windows系统中我们知道&#xff0c;装一个Windows下的NVIDIA驱动是多么容易&#xff0c;然而&#xff0c;在Linux下如何安装NVIDIA驱动是一件多么“快乐”的事。。。 1、驱动下载 首先进入NVIDIA官网下载Linux的闭源驱动&#xff1a;NVIDIA官网驱动下载 找到对应显卡的驱动&a…

win10PC上安装deepin深度Linux系统简易教程

今天突然刷到deepin系统的新闻&#xff0c;心血来潮&#xff0c;自己电脑上安装一个&#xff0c;说干就干&#xff0c;总共分这么几个步骤&#xff1a; 1、在win10建立磁盘分区&#xff0c;用于后面步骤 &#xff08;1&#xff09;右击<我的电脑>&#xff0c;点击管理 …

Deepin安装教程

安装教程 制作&#xff35;盘安装盘&#xff0c;优先使用deepin提供工具进行制作&#xff1a;下载地址deepin-boot-maker。支持的系统包括Windows&#xff0c;linux&#xff0c;还有MacOS。其中linux下的安装包&#xff0c;目前官方未提供&#xff0c;可能需要自己编译。如果本…