【OJ相关】validator (UOJ / codeforces)

来源:互联网 发布:怎样设置网站主域名 编辑:程序博客网 时间:2024/05/18 00:05

Background

要在自己的测评网站(或者你是UOJ啊cf啊什么的题目管理员)开启Hack,检验别人给的数据是一大关键。然而……

因此你要写validator(val.cpp)判合法性。然而cf上的讲解是英文的,UOJ的document里面似乎又没有讲,于是靠着看cf+自己摸索搞了一点validator的经验。

Description

首先无论是在UOJ还是cf,validator是建立在testlibrary的基础上的(即testlib),所以在val的开头,你需要写:

#include "testlib.h"

去引用那个只有3490行的头文件。

同时在main函数的开头,你需要写:

registerValidation();

大概可能是申明这是个validator,在调用这条语句以后,你可以调用以”inf.“(输入流)开头的指令。

Task

Input

接下来就是读别人给的数据了。

如何读?看下面这条代码:

int n = inf.readInt();

这条语句不加限制地读入了一个int。但是如果我们要给他一个范围呢?可以用接下来讲的ensure判定,但是下面这条语句简洁地规范了n的取值范围。

int n = inf.readInt(L, R)

这条语句限制n的范围是[L, R],如果不合法就直接fail了。

使用下面这个函数,在函数变量后加一个string表示其名称,可以更方便调试和给出fail信息:

int n = inf.readInt(L, R, "n");

在这种情况下越界fail会出现如下提示:

FAIL Integer parameter [name=n] equals to XXXX, violates the range [L, R] (stdin)

(以上的XXXX,L,R均为具体值)


除此之外,inf.read型的指令有如下一些:

char readChar(); //读入一个字符char readChar(char c); //读入一个字符,但保证为c,否则不合法char readSpace(); //读入保证一个空格,同readChar(' '),不为空格不合法string readToken();string readWord(); //读词,不含空格和换行等string readToken(string regex);string readWord(string regex); //读词,但保证和regex相同long long readLong();long long readLong(long long L, long long R); //读long long,可以有上下界限制。int readInt();int readInt(int L, int R);int readInteger();int readInteger(int L, int R); //读int,可以有上下界限制。double readReal();double readDouble()double readReal(double L, double R);double readDouble(double L, double R); //读double,可以有上下界限制double readStrictReal(double L, double R, int minPrecision, int maxPrecision);double readStrictDouble(double L, double R, int minPrecision, int maxPrecision);//在读double并控制上下界的同时控制其精度,保证小数点后位数在[minPrecision, maxPrecision]范围string readString();string readLine(); //读行读入string,不读EOLN,但是输入流指针移向下一行void readEoln(); //读EOLN,包括#13和#10(Linux下仅#10),读不到failvoid readEof(); //读EOF,读不到failvoid unreadChar(char c); //把字符c退回读入流

(以上部分引自codeforces)

Output

仅仅读入是不行的,我们要加入一定量的判断:

ensure(bool condition);

这条语句要求保证condition为真,即成立。对于下面这个例子,不成立会有如下结果:

ensure(x > y);

FAIL Condition failed: “x > y”

另外,ensure可以增加自己的提示语句,但是命令要换为ensuref:

ensuref(bool condition, string hint);

同样要求condition为真,并且fail的话会出现字符串hint。同样可以用%d%s等插入变量。如下例:

ensuref(x > y, "x should be more than y, but your x = %d, y = %d", x, y);

FAIL x should be more than y, but your x = XXX, y = XXX

总体来讲validator写法就完结了,接下来看几个实例。

Sample

Sample1

输入一个整数n,在区间[2, 500],不要多余空格,然后EOLN,EOF。

方法:read时加入区间限制即可

#include "testlib.h"#include <bits/stdc++.h>using namespace std;int main(){    registerValidation();    int n = inf.readInt(2, 500, "n");    inf.readEoln();    inf.readEof();}

Sample2

如果不是在读入时就能简单判断呢,例如读n 5000,opt;opt为0时n应为奇数,而opt为1时n 4000。
很简单,读进来以后加if。

#include "testlib.h"#include <bits/stdc++.h>using namespace std;int main(){    registerValidation();    int n = inf.readInt(0, 5000, "n");    inf.readSpace();    int o = inf.readInt(0, 1, "opt");    if (o == 1)        ensuref(n <= 4000, "When opt = 1, n must be less than 4000");    else        ensuref(n & 1, "When opt = 0, n must be an even number");    inf.readEoln();    inf.readEof();}

Sample3

题面数据移步UOJ#79 一般图最大匹配。
这个题一个是要去自环,另一个是不可以一条边描述多次,于是拿一个pair的set或者之类的东西记一下就可以了。
以下是UOJ开源提供的示范validator:

#include "testlib.h"#include <set>using namespace std;int main(){    registerValidation();    int n = inf.readInt(2, 500, "n");    inf.readSpace();    int m = inf.readInt(1, 124750, "m");    inf.readEoln();    set< pair<int, int> > es;    for (int i = 0; i < m; i++){        int v = inf.readInt(1, n, "v");        inf.readSpace();        int u = inf.readInt(1, n, "u");        inf.readEoln();//读边        ensuref(v != u, "this graph contains self loops");//查自环        ensuref(!es.count(make_pair(v, u)), "duplicate edges");//查重边        es.insert(make_pair(v, u));        es.insert(make_pair(u, v));    }    inf.readEof();}

Conclusion

validator很好写吧!祝您早日成为办OJ大神!

原创粉丝点击