Super Online Judge支持五种赛制,分别为:ACM/ICPC、Normal-OI、OPJ-OI、Codeforces、Topcoder
ACM/ICPC是国际大学生程序设计竞赛。在ACM/ICPC赛制下,比赛时可查看自己提交的代码的评测结果,也可随时观看实时排名。 当比赛结束后,会公布所有人的代码与评测结果。 题目只有通过/不通过两种结果,没有部分分。 选手通过某题时,计算罚时,罚时为本题目未通过的提交次数*20分钟。 最终排名以通过题目数为第一关键字,罚时为第二关键字的方式计算。
OI竞赛为中学生信息学奥林匹克竞赛,其中包括NOIP、NOI、IOI等赛事。在OI赛制下,比赛时选手提交代码的评测结果不可见,他人提交的代码不可见,实时排名亦不可见。 当比赛结束后,会公布比赛排名、所有选手代码和所有提交记录评测结果。 题目有部分分,选手相应题目的得分按照他最后一次提交的评测结果不是“编译失败”的记录的得分计算。
OpenJudge OI的评测方式则允许实时查看评测结果,并且有部分分,排名以总分为第一关键字降序排名,如果分数相同则以提交次数为第二关键字升序排名。
Codeforces赛制分为两个阶段,Pretest阶段和System Test阶段,前者从比赛开始至比赛结束,在此期间用户提交程序需通过数据库中标记为Pretest的测试数据,通过后可以获得基础分,如果通过前存在没有通过全部Pretest的记录,且至少通过了一个Pretest测试点,每条记录将被扣50分。通过Pretest后,您可以选择锁定该题目,锁定后此题将无法继续提交,但可以查看他人代码,并且设计测试数据使对方程序运行错误,如果成功将获得100分加成,否则被扣50分。比赛结束后系统将进行System Test,将所有通过Pretest的记录进行重测,重测时数据为Pretest数据、系统完整数据和比赛过程中Hack成功的所有数据。最终排名也会随之变化。
基础分的算法为:基础分 = 题目分值 * (1 - 0.004 * 分钟数)
每条记录只能被Hack一次,被成功Hack后,该选手的该题得分将清零直至再次通过Pretest,该选手再次提交时,Pretest中将增加之前Hack的数据,只有通过Pretest点及Hack数据才算通过Pretest。
在Super Online Judge上,将不执行Room分配机制。
TopCoder赛制分为三个阶段:解题阶段、中场休息、Hack阶段,解题阶段时,打开任意题目,相应题目开始计算动态分,成功通过样例则计入本题分数,Hack阶段选手可以查看任意其他人的代码,并且进行Hack。
评测机采用Super Online Judge Core内核,其中部分评测服务器为Linux操作系统,部分评测服务器为Windows操作系统,因此您在使用int64类型时应当使用%lld,在使用uint64类型时应使用%llu。
下面是各个编译器的版本以及编译参数
语言 | 编译器及版本 | 编译命令行 | 运行命令行 |
---|---|---|---|
C | MinGW GCC 4.8.1 | g++ -O2 -o Main.exe -DONLINE_JUDGE -lm --static --std=c99 Main.c | Main |
C++ | MinGW G++ 4.8.1 | g++ -O2 -o Main.exe -DONLINE_JUDGE -lm --static --std=c++98 Main.cpp | Main |
C++ 11 | MinGW G++ 4.8.1 | g++ -O2 -o Main.exe -DONLINE_JUDGE -lm --static --std=c++11 Main.cpp | Main |
Java | JDK 1.7 | javac Main.java | java Main |
Pascal | Free Pascal 2.6 | fpc -O2 -dONLINE_JUDGE Main.pas | Main |
Python | Python 2.7 | 脚本语言无需编译 | python Main.py |
Python | Python 3.3 | 脚本语言无需编译 | python Main.py |
Ruby | Ruby 2.0.0 | 脚本语言无需编译 | ruby Main.rb |
C# | .Net 4.0 | csc Main.cs | Main |
VB.Net | .Net 4.0 | vbc Main.vb | Main |
注册成为Super Online Judge会员后,你将有初始的1500点能力值,当您参加评级赛后,该分数将会根据您的答题情况增减。
每场评级赛均有等级区分,从低等级至高等级分别为:R, L3, L2, L1, S
评级R:选手能力值低于1500,昵称为默认颜色。
评级L3:选手能力值1500~1700,昵称为绿色。
评级L2:选手能力值1700~2000,昵称为天蓝色。
评级L1:选手能力值2000~2400,昵称为橙色。
评级S:选手能力值大于2400,昵称为红色。
任何用户都可以举办比赛,比赛可以是私有的,需要通过输入正确的密码才能参加比赛,也可以是公开的,允许任何人参加比赛。
如果比赛欲获得官方支持,升级为评级赛,请在创建比赛时勾选相应选项,并给出每个题目的能力值评估,同时每题均提交高质量的解题报告,以便Super Online Judge官方审核,同时您至少留出3天的时间,让Super Online Judge进行审核。
成功创建比赛后,您可以设定比赛管理员以及比赛志愿者,比赛管理员可以和您一样修改比赛题目、在答疑系统中给予选手回复,志愿者则可通过电脑、手机客户端获取到选手通过题目情况,客户端会给出分发气球(仿真ACM/ICPC赛制)的建议以及需要打印的材料(如果该场比赛勾选了允许提交打印材料)。
传统的评测方式是去行末空格与文末回车,如果您出的题目正好是需要按照此方式进行校验,则您只需提供题目的输入数据与输出数据。
如果您提交的题目是多解题目,则需编写Special Judge,Special Judge程序负责校验选手程序结果,评测机通过命令行调用,同时传递三个参数,分别为:答案文件位置,选手输出文件位置,输入文件位置。
下面是一个特殊比较器的例子
#include <cassert> #include <cstdio> #include <cstdlib> #include <cstring> //一些定义 const int ACCEPT = 0; const int WRONG_ANSWER = 1; //fstd 标准输出 fout 选手输出 fin 标准输入 FILE *fstd,*fout,*fin; int LastCharStd = -2,LastCharOut=-2; //检查下一个字符 inline int Peek(FILE* f){ if(f==fstd){ if(LastCharStd == -2) LastCharStd=fgetc(f); return LastCharStd; }else{ if(LastCharOut == -2) LastCharOut=fgetc(f); return LastCharOut; } } //取出下一个字符 inline void Pop(FILE* f){ if(f==fstd){ if(LastCharStd == -2) fgetc(f); else LastCharStd = -2; }else{ if(LastCharOut == -2) fgetc(f); else LastCharOut = -2; } } //判断字符是否为空白 inline bool IsSpace(int ch){ return ch>=0 && (ch<=32 || ch>=127); } //执行比较操作。 bool DoCompare(){ int stdPosition=0,outPosition=0; bool stdInSpace=true,outInSpace=true; while(true){ int stdC=Peek(fstd),outC=Peek(fout); if(stdC==EOF && outC==EOF){ return true; }else if(stdC==EOF && IsSpace(outC)){ outPosition++; Pop(fout); }else if(outC==EOF && IsSpace(stdC)){ stdPosition++; Pop(fstd); }else if(IsSpace(stdC) && IsSpace(outC)){ stdPosition++; outPosition++; stdInSpace=true; outInSpace=true; Pop(fstd); Pop(fout); }else if(IsSpace(stdC) && outInSpace){ stdPosition++; Pop(fstd); }else if(IsSpace(outC) && stdInSpace){ outPosition++; Pop(fout); }else if(stdC==outC){ stdPosition++; outPosition++; stdInSpace=false; outInSpace=false; Pop(fstd); Pop(fout); }else{ printf("答案文件的第%d字节",stdPosition+1); if(stdC==EOF){ printf("<eof>"); }else{ printf("0x%x",stdC); } printf("不能匹配输出文件的第%d字节",outPosition+1); if(outC==EOF){ printf("%lt;EOF%gt;"); }else{ printf("0x%x",outC); } puts(""); return false; } } } int main(int argc, char* argv[]) { if(argc!=4){ printf("参数不足 %d",argc); return -1; } //打开文件 if(NULL==(fstd=fopen(argv[1],"r"))){ return -1; } if(NULL==(fout=fopen(argv[2],"r"))){ return -1; } if(NULL==(fin=fopen(argv[3],"r"))){ return -1; } if(DoCompare()){ return ACCEPT; }else{ return WRONG_ANSWER; } }
如果您的比赛赛制设定为Codeforces或TopCoder,您需要为每个题目设置一个数据范围校验器,使用这个校验器来读取选手提交上来的数据,并检验其合法性,如果合法,程序返回0,否则返回其他值。
您可以在数据范围校验器中调用Judge.hpp头文件,该头文件的源代码如下:
#ifndef _JUDGE_HPP_
#define _JUDGE_HPP_
#include <cstdio>
#include <cctype>
#include <climits>
#include <cstdlib>
#include <vector>
#include <string>
#include <istream>
#include <ostream>
#include <sstream>
#include <iostream>
namespace Judge
{
using std::string;
using std::vector;
using std::istream;
using std::ostream;
using std::stringstream;
string ReadLine(istream&);//读取一行,不写参数默认为标准输入cin
void WriteLine(string, ostream&);//输出一行,只写第一个参数默认为标准输出cout
bool IsEof(istream&);//判断是否是文件末,不写参数默认为标准输入cin
vector<string> Split(string, string);//按第二个字符串分割第一个字符串,默认按空格分割
string TrimEnd(string, char);
string TrimBegin(string, char);
string Trim(string, char);
string Replace(string, string, string);
template<class T>
string ToString(T);
string ToString(double, int);//Int is len and max_len is 100
int ToInt32(string);
unsigned int ToUInt32(string);
long long ToInt64(string);
unsigned long long ToUInt64(string);
double ToDouble(string);
long double ToLongDouble(string);
const char* ToCharPtr(string);
string ReadLine(istream &stream = std::cin)
{
string temp;
std::getline(stream, temp);
return temp;
}
void WriteLine(string str, ostream &stream = std::cout)
{
stream << str << std::endl;
}
template<class T>
void readFromStr(string str, T &temp)
{
stringstream ss(str);
ss >> temp;
}
bool isEmpty(string str)
{
if(str.empty()) return 1;
for(size_t i=0; i<str.size(); ++i)
if(!isspace(str[i]))
return 0;
return 1;
}
bool checkDigit(string str)
{
for(size_t i=0; i<str.size(); ++i)
if(!isdigit(str[i]))
return 0;
return 1;
}
bool cmpNumStr(string lhs, string rhs)
{
if(lhs.size() != rhs.size()) return lhs.size() > rhs.size();
return lhs > rhs;
}
bool IsEof(istream &stream = std::cin)
{
string line;
while(!stream.eof())
{
line = ReadLine(stream);
if(!isEmpty(line)) return 0;
}
return 1;
}
int ToInt32(string str)
{
static const string INTMAXSTR = ToString(INT_MAX);
static const string INTMINSTR = ToString(INT_MIN);
if(isEmpty(str)) exit(-1);
bool isNeg = str[0]=='-';
if(isNeg && str.size()==1) exit(-1);
if(!checkDigit(str.substr(isNeg))) exit(-1);
if(isNeg && cmpNumStr(str, INTMINSTR)) exit(-1);
if(!isNeg && cmpNumStr(str, INTMAXSTR)) exit(-1);
int temp;
readFromStr(str, temp);
return temp;
}
unsigned int ToUInt32(string str)
{
static const string UINTMAXSTR = ToString(UINT_MAX);
if(isEmpty(str)) exit(-1);
if(!checkDigit(str)) exit(-1);
if(cmpNumStr(str, UINTMAXSTR)) exit(-1);
unsigned int temp;
readFromStr(str, temp);
return temp;
}
long long ToInt64(string str)
{
static const string LLMAXSTR = ToString(LLONG_MAX);
static const string LLMINSTR = ToString(LLONG_MIN);
if(isEmpty(str)) exit(-1);
bool isNeg = str[0]=='-';
if(isNeg && str.size()==1) exit(-1);
if(!checkDigit(str.substr(isNeg))) exit(-1);
if(isNeg && cmpNumStr(str, LLMINSTR)) exit(-1);
if(!isNeg && cmpNumStr(str, LLMAXSTR)) exit(-1);
long long temp;
readFromStr(str, temp);
return temp;
}
unsigned long long ToUInt64(string str)
{
static const string ULLMAXSTR = ToString(ULLONG_MAX);
if(isEmpty(str)) exit(-1);
if(!checkDigit(str)) exit(-1);
if(cmpNumStr(str, ULLMAXSTR)) exit(-1);
unsigned long long temp;
readFromStr(str, temp);
return temp;
}
double ToDouble(string str)
{
if(isEmpty(str)) exit(-1);
size_t point = str.find(".");
if(point==string::npos && !checkDigit(str.substr(str[0]=='-'))) exit(-1);
if(point!=string::npos && (!checkDigit(str.substr(point+1)) || !checkDigit(str.substr(str[0]=='-', point-(str[0]=='-'))))) exit(-1);
double temp;
readFromStr(str, temp);
return temp;
}
long double ToLongDouble(string str)
{
if(isEmpty(str)) exit(-1);
size_t point = str.find(".");
if(point==string::npos && !checkDigit(str.substr(str[0]=='-'))) exit(-1);
if(point!=string::npos && (!checkDigit(str.substr(point+1)) || !checkDigit(str.substr(str[0]=='-', point-(str[0]=='-'))))) exit(-1);
long double temp;
readFromStr(str, temp);
return temp;
}
template<class T>
string ToString(T num)
{
stringstream ss;
ss << num;
string temp;
ss >> temp;
return temp;
}
string ToString(double num, int len)
{
char temp[102];
if(len<0 || len>100) exit(-1);
sprintf(temp, "%.*lf", len, num);
return string(temp);
}
const char* ToCharPtr(string str)
{
return str.c_str();
}
string TrimBegin(string Source, char c = ' ')
{
string::iterator it = Source.begin();
while(it!=Source.end() && *it==c)
++it;
Source.erase(Source.begin(), it);
return Source;
}
string TrimEnd(string Source, char c = ' ')
{
string::iterator it = Source.end();
while(it!=Source.begin() && *(it-1)==c)
--it;
Source.erase(it,Source.end());
return Source;
}
string Trim(string Source, char c = ' ')
{
Source = Judge::TrimBegin(Source, c);
Source = Judge::TrimEnd(Source, c);
return Source;
}
string Replace(string Source, string str1, string str2)
{
string res = "";
size_t last = 0, pos = 0, len1 = str1.size();
while((pos = Source.find(str1, pos)) != string::npos)
{
res.append(Source.substr(last, pos-last));
res.append(str2);
last = pos = pos+len1;
}
res.append(Source.substr(last));
return res;
}
vector<string> Split(string Source, string str = " ")
{
vector<string> res;
size_t last = 0, pos = 0, len = str.size();
while((pos = Source.find(str, pos)) != string::npos)
{
res.push_back(Source.substr(last, pos-last));
last = pos = pos+len;
}
res.push_back(Source.substr(last));
return res;
}
}
#endif // _JUDGE_HPP_
如果您的比赛赛制设定为Codeforces或TopCoder,您需要为每个题目设置一个标程,该标程必须是本题正确的算法,系统将选手通过数据范围校验器的数据注入到本程序中,取出本程序的结果,与选手程序输出的结果对比。