受【原创】Cena万能AC程序研究报告 - By RogerRo
http://tieba.baidu.com/p/2475712472
一贴启发所写,感谢RogerRo提供他使用的测试数据。
优点:效率实在高,保证能AC。
缺点:我们必须提条件,不满足条件的对不起了。
0、必须是Pascal用户,C++/C用户对不起了,这个整体思路不可移植
1、有这样一个契机,这代码才有用:
Cena自带的Pascal编译器是2.0.4,而且还没有math库,这让很多人觉得不爽。
我们机房采用这样一种做法:
把Cena的Pascal代码编译器路径直接指向FPC(默认的完全安装的FPC)的编译器的路径,而且并没有删除竞赛不允许使用的除system和math库以外的其他库。
FPC完全安装和Cena编译器路径直接指向FPC编译器路径(FPC\2.4.0\bin\i386-win32\ppc386.exe)这两条件缺一不可!
注:如果有任何一个条件不成立,那还是用RogerRo的办法吧,不能完全AC但也够了。
满足条件?那我们看看思路:
首先分析出输入文件和输出文件的对应关系,然后找到现在是哪一个输入文件,最后输出对应的输出文件。
根据RogerRo的分析,Cena的测试数据配置文件在\data\dataconf.xml文件里,而此文件是一个.gz的压缩包,解压出来才是一个能用于分析的xml文件。
不要小看FPC,千万不要。
FPC在多平台下发展到这个程度,他能,也应该做得很全面。
fpc的doc里有个fcl.pdf,介绍了其fcl库的功能。
我们这次需要用的是fcl的xml和zlib有关的功能。
第一个问题,如何复制一个文件?(而且要高效)
(自定义安装,不安装units,只要还有classes、objects这两个,下述复制方法也可以用)
读一行写一行,以FPC的文件读写效率,当你在前面找过那么多测试数据以后,剩下的时间不多了,再复制一下大输出文件……最朴素的办法肯定和这个最奔放的办法不搭界。
在FPC的units未被阉割的情况下,还有个classes、objects,他们有文件复制、读写神器——tfilestream
tfilestream是一个类。先创建一下这个类,关联文件,然后你可以选择从这个类中读取,也可以选择从另一个tfilestream中复制过来。
详见以下代码演示:
uses math,classes;
const bufsize=1000;
var fstreama,fstreamb:tfilestream;
inputbuf,tempbuf:array[1..bufsize]of char;
fstreama:=tfilestream.create('a.txt',fmopenread);
//要用这样的方式创建一个tfilestream对象
//第一个参数表示关联的文件,可以用绝对路径,也可以用相对路径
//第二个参数表示打开方式,可参阅rtl.pdf。fmopenread表示只读打开
//下面的fmcreate和rewrite有类似的效果,创建一个文件。
fstreamb:=tfilestream.create('b.txt',fmcreate);
//关联b.txt,创建,打开
fstreama.read(inputbuf,min(fstreama.size,bufsize));
//从fstreama关联的文件中读取数据
//第一个参数表示读取到的缓冲区,可以用string,也可以用char的数组
//第二个参数表示可以读进来的大小
//如果大于文件大小,出错,一个字也读不进来
//如果大于缓冲区大小,也出错
//用min(fstreama.size,bufsize)这样的写法来保证不会出错
fstreamb.copyfrom(fstreama,fstreama.size);
//从fstreama中复制内容到fstreamb,这样,fstreamb关联的文件和fstreama关联的文件将一模一样。
fstreama.free;
fstreamb.free;
//释放对象,这是良好习惯。
//本来应该写在try...finally...end;里,但是要开objpas或delphi才行,那还是算了。 用上述方法,效率比你手写的要高不说,复制的方法还适用于任何文件。
那这样我们可以完成复制dataconf.xml文件的过程了:
procedure copyconf;
var source,locate:tfilestream;
const oringin='..\data\dataconf.xml';
//用相对路径。程序执行在\tmp下,dataconf.xml在先退回上一层,然后data文件夹里
goal='dataconf.xml';
begin
source:=tfilestream.create(oringin,fmopenread);
locate:=tfilestream.create(goal,fmcreate);
locate.copyfrom(source,source.size);
source.free;
locate.free;
end;
第二个问题,解压缩dataconf.xml。
这里我们要用到zstream里的tgzfilestream。
看上去和tfilestream有关系吧?没错,两者都继承自tstream。但是,zstream好像有点小问题,详见下面的描述。
tgzfilestream的用法和tfilestream的用法比较像,毕竟都是流。
首先关联文件,然后一个个字符读取,读取出来的全是解压缩了的字符,把读取出来的结果放到另一个文件里去就行。
直接看代码吧。
uses zstream,classes;
procedure unzipconf;
const readfilename='dataconf.xml';
outfilename='dataconf.out';
var archstream:tgzFileStream;
filestream:tfilestream;
c:char;
begin
archstream:=tgzfilestream.create(readfilename,gzopenread);
//就是第二个参数fmopenread改成gzopenread而已
filestream:=tfilestream.create(outfilename,fmcreate);
while archstream.read(c,sizeof(c))>0 do
filestream.write(c,sizeof(c));
//tfilestream.write的参数和read的参数一样的意思,先是缓冲区,然后是缓冲区大小
//效果是往这个流(就是文件里)写入缓冲区的内容
//为什么这里不用copyfrom?
//虽说tgzfilestream也有size属性,但是我不知道为什么,我一访问一定出错
//那没办法,逐字符读取吧,直到没有再读入任何字符。
archstream.free;
filestream.free;
end;
第三步:读入提供的输入文件,放到缓冲区
const filename='maowant';
inputfile=filename+'.in';
outputfile=filename+'.out';
fstreama:=tfilestream.create(inputfile,fmopenread);
fstreama.read(inputbuf,min(fstreama.size,bufsize));
fstreama.free;
不做解释了。
http://tieba.baidu.com/p/2475712472
一贴启发所写,感谢RogerRo提供他使用的测试数据。
优点:效率实在高,保证能AC。
缺点:我们必须提条件,不满足条件的对不起了。
0、必须是Pascal用户,C++/C用户对不起了,这个整体思路不可移植
1、有这样一个契机,这代码才有用:
Cena自带的Pascal编译器是2.0.4,而且还没有math库,这让很多人觉得不爽。
我们机房采用这样一种做法:
把Cena的Pascal代码编译器路径直接指向FPC(默认的完全安装的FPC)的编译器的路径,而且并没有删除竞赛不允许使用的除system和math库以外的其他库。
FPC完全安装和Cena编译器路径直接指向FPC编译器路径(FPC\2.4.0\bin\i386-win32\ppc386.exe)这两条件缺一不可!
注:如果有任何一个条件不成立,那还是用RogerRo的办法吧,不能完全AC但也够了。
满足条件?那我们看看思路:
首先分析出输入文件和输出文件的对应关系,然后找到现在是哪一个输入文件,最后输出对应的输出文件。
根据RogerRo的分析,Cena的测试数据配置文件在\data\dataconf.xml文件里,而此文件是一个.gz的压缩包,解压出来才是一个能用于分析的xml文件。
不要小看FPC,千万不要。
FPC在多平台下发展到这个程度,他能,也应该做得很全面。
fpc的doc里有个fcl.pdf,介绍了其fcl库的功能。
我们这次需要用的是fcl的xml和zlib有关的功能。
第一个问题,如何复制一个文件?(而且要高效)
(自定义安装,不安装units,只要还有classes、objects这两个,下述复制方法也可以用)
读一行写一行,以FPC的文件读写效率,当你在前面找过那么多测试数据以后,剩下的时间不多了,再复制一下大输出文件……最朴素的办法肯定和这个最奔放的办法不搭界。
在FPC的units未被阉割的情况下,还有个classes、objects,他们有文件复制、读写神器——tfilestream
tfilestream是一个类。先创建一下这个类,关联文件,然后你可以选择从这个类中读取,也可以选择从另一个tfilestream中复制过来。
详见以下代码演示:
uses math,classes;
const bufsize=1000;
var fstreama,fstreamb:tfilestream;
inputbuf,tempbuf:array[1..bufsize]of char;
fstreama:=tfilestream.create('a.txt',fmopenread);
//要用这样的方式创建一个tfilestream对象
//第一个参数表示关联的文件,可以用绝对路径,也可以用相对路径
//第二个参数表示打开方式,可参阅rtl.pdf。fmopenread表示只读打开
//下面的fmcreate和rewrite有类似的效果,创建一个文件。
fstreamb:=tfilestream.create('b.txt',fmcreate);
//关联b.txt,创建,打开
fstreama.read(inputbuf,min(fstreama.size,bufsize));
//从fstreama关联的文件中读取数据
//第一个参数表示读取到的缓冲区,可以用string,也可以用char的数组
//第二个参数表示可以读进来的大小
//如果大于文件大小,出错,一个字也读不进来
//如果大于缓冲区大小,也出错
//用min(fstreama.size,bufsize)这样的写法来保证不会出错
fstreamb.copyfrom(fstreama,fstreama.size);
//从fstreama中复制内容到fstreamb,这样,fstreamb关联的文件和fstreama关联的文件将一模一样。
fstreama.free;
fstreamb.free;
//释放对象,这是良好习惯。
//本来应该写在try...finally...end;里,但是要开objpas或delphi才行,那还是算了。 用上述方法,效率比你手写的要高不说,复制的方法还适用于任何文件。
那这样我们可以完成复制dataconf.xml文件的过程了:
procedure copyconf;
var source,locate:tfilestream;
const oringin='..\data\dataconf.xml';
//用相对路径。程序执行在\tmp下,dataconf.xml在先退回上一层,然后data文件夹里
goal='dataconf.xml';
begin
source:=tfilestream.create(oringin,fmopenread);
locate:=tfilestream.create(goal,fmcreate);
locate.copyfrom(source,source.size);
source.free;
locate.free;
end;
第二个问题,解压缩dataconf.xml。
这里我们要用到zstream里的tgzfilestream。
看上去和tfilestream有关系吧?没错,两者都继承自tstream。但是,zstream好像有点小问题,详见下面的描述。
tgzfilestream的用法和tfilestream的用法比较像,毕竟都是流。
首先关联文件,然后一个个字符读取,读取出来的全是解压缩了的字符,把读取出来的结果放到另一个文件里去就行。
直接看代码吧。
uses zstream,classes;
procedure unzipconf;
const readfilename='dataconf.xml';
outfilename='dataconf.out';
var archstream:tgzFileStream;
filestream:tfilestream;
c:char;
begin
archstream:=tgzfilestream.create(readfilename,gzopenread);
//就是第二个参数fmopenread改成gzopenread而已
filestream:=tfilestream.create(outfilename,fmcreate);
while archstream.read(c,sizeof(c))>0 do
filestream.write(c,sizeof(c));
//tfilestream.write的参数和read的参数一样的意思,先是缓冲区,然后是缓冲区大小
//效果是往这个流(就是文件里)写入缓冲区的内容
//为什么这里不用copyfrom?
//虽说tgzfilestream也有size属性,但是我不知道为什么,我一访问一定出错
//那没办法,逐字符读取吧,直到没有再读入任何字符。
archstream.free;
filestream.free;
end;
第三步:读入提供的输入文件,放到缓冲区
const filename='maowant';
inputfile=filename+'.in';
outputfile=filename+'.out';
fstreama:=tfilestream.create(inputfile,fmopenread);
fstreama.read(inputbuf,min(fstreama.size,bufsize));
fstreama.free;
不做解释了。