Loading

关于lemon的spj和交互题的配置

Lemonlime

SPJ

首先是 spj.cpp 的写法,下面是 \(lemon\) 的写法(一些线上 \(OJ\) 的写法都和 \(luogu\) 的类似,洛谷写的挺详细的,挂个链接):

模板



#include <bits/stdc++.h>
#include <climits>
#include <algorithm>
#include <fstream>//模板粘下来就行

using namespace std;
const int N = 5e5 + 10;
int n,nn;
int a[N],b[N] , an[N], bn[N],d[N];
bool vis[N];
vector<int>q[N];
set<int>p[N];
ifstream fin,fout,fstd;//模板粘下来就行
ofstream fscore,freport;//模板粘下来就行
void dfs(int u) {
	vis[u]=0;
	for(auto v:q[u]) {
		if(p[u].find(v)!=p[u].end()||vis[v]) {
			continue;
		}
	}
}
int main(int argc , char *argv[]) { //模板粘下来就行
    fin.open(argv[1]);//打开data的.in文件
	fout.open(argv[2]);//打开选手的输出文件
    fstd.open(argv[3]);//打开data的.out文件,对于部分题目没有也可以
	fscore.open(argv[5]);//判分用的
    int sc = atoi(argv[4]);//这个会返回每个点多少分
	int jd = 1;//得分的权重,最后返回sc*jd
	fin >> n; //这个会读入.in的文件
	for(int i=1;i<=n;i++) {
		fin >> a[i] >> b[i];d[a[i]]++;d[b[i]]++;
		q[a[i]].push_back(b[i]);
		q[b[i]].push_back(a[i]);
	}
	int k;
	fstd >> k;//这个会读入data的.out文件里的数据
	fout >> nn;//这个会读入选手的输出文件里的数据
	if(nn>n+1) jd=0;
	if(k==-1) {
		if(nn!=-1) jd=0;
	}
	else {
		for(int i=1;i<=nn;i++) {
			fout>>an[i]>>bn[i];d[an[i]]--;d[bn[i]]--;
			p[an[i]].insert(bn[i]);
			p[bn[i]].insert(an[i]);
		}
		dfs(1);
		int f=0;
		for(int i=1;i<=n;i++) {
			if(vis[i]!=1) f=1;
			if(d[i]==0) jd=0;
		}
		if(f==0) jd=0;
	}
	fscore << sc * jd << endl;//输出选手得分用的
	fin.close();
    fout.close();
    fstd.close();
    fscore.close();
    return 0;
}


代码里有详细的注释,具体的写法因题而异。

配置

然后就是 \(lemon\) 的配置,这里以 \(lemonlime\) 为例,这个黄 \(lemon\) 也是同样的:

交互题:

这里以函数交互为例(IO交互一般可以转化成函数交互):

首先你需要写一个 grader.cpp


#include "a.h" //这是自己编写的 .h 文件,下面会有写法
#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
int n,lim,ask_num;
string S;
int Ask(string s) {//选手可以调用的函数
    int res=0; ask_num++;
    if(ask_num>lim) {
        cout<<"NO";exit(0);
    }
    for(int i=0;i<n;i++) {
        if(s[i]==S[i]) {
            res++;
        }
    }
    return res;
}
signed main() {
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    cin>>n>>lim>>S;
    string ans=solve(n,lim);//选手应该实现的函数
    if(lim>ask_num) {//对于询问次数的限制
        cout<<"NO";
        return 0;
    }
    for(int i=0;i<n;i++) {
        if(ans[i]!=S[i]) {
            cout<<"NO";
            return 0;
        }
    }
    cout<<"YES";
    return 0;
}

下面是 .h 的写法:


#include<bits/stdc++.h>
using namespace std;
int Ask(string s);
string solve(int n,int lim);

这样 .h 的文件就是一个桥梁的作用。

当然这样写在选手实现的函数里面也应该调用 .h 也就是在自己的文件开头加上 #include "a.h" 这样就可以正常调用函数了。

这是 \(lemonlime\) 的配置:

不同的写法:

一种是有 .h 文件的(就是上面的示例)。

另一种是不写 .h 文件的,具体的就是需要在 grader.cpp 中调用选手实现的函数,也就是声明一下这个函数,这种情况选手实现的函数的全局变量不应该与 grader.cpp 里的变量重名,配置 \(lemon\) 时,交互库路径和交互库名称 这两栏就空着,不写东西。

一种是在 grader.cpp 里写 freopen 不选 定向到标准输入和定向到标准输出(就是上面的示例)。

另一种是不在 grader.cpp 里写 freopen定向到标准输入和定向到标准输出

重点:

交互题一般有一个判断是否正确的一个东西,我们这里称作密匙,少数情况下只判断答案正确与否的话,就把密匙放在 data.out 文件里,这种情况选手下发文件的 grader.cpp 的密匙与 data 的密匙不一样,这样就是防止选手攻击交互库,但是交互题大多数的判分标准是询问次数,所以一般与 spj 配合食用。

它们两者之间并不冲突,所以可以同时书写放在 data 里面。


关于lenmon的注意事项:

  1. 配置交互题的时候,返回 超出时间限制 ,有时候是 不同写法2 中的一些东西冲突了,或是读入不全,就是读入的比 data 里的多。

  2. 返回编译错误,ld returned 1 就是已经运行了,可能是 grader.cpp 运行了没关,重新测评或者请一下后台。

  3. 返回 程序不能运行 检查编译器版本是否符合计算机版本,一般是 64 位和 32 位冲突了。

posted @ 2025-09-27 16:50  dfgz  阅读(147)  评论(5)    收藏  举报