在C ++中输入输出时我只使用了scanf / printf和cin / cout。现在我最近遇到了this代码,以一种奇怪的方式进行I / O.
另请注意,此I / O方法导致代码运行速度极快,因为此代码使用与大多数其他代码几乎相同的算法,但它在更短的时间内执行。为什么这个I / O如此之快以及这一般如何工作?
编辑:代码
#include <bits/stdtr1c++.h>
#define MAXN 200010
#define MAXQ 200010
#define MAXV 1000010
#define clr(ar) memset(ar, 0, sizeof(ar))
#define read() freopen("lol.txt", "r", stdin)
using namespace std;
const int block_size = 633;
long long res, out[MAXQ]; int n, q, ar[MAXN], val[MAXN], freq[MAXV];
namespace fastio{
int ptr, ye;
char temp[25], str[8333667], out[8333669];
void init(){
ptr = 0, ye = 0;
fread(str, 1, 8333667, stdin);
}
inline int number(){
int i, j, val = 0;
while (str[ptr] < 45 || str[ptr] > 57) ptr++;
while (str[ptr] > 47 && str[ptr] < 58) val = (val * 10) + (str[ptr++] - 48);
return val;
}
inline void convert(long long x){
int i, d = 0;
for (; ;){
temp[++d] = (x % 10) + 48;
x /= 10;
if (!x) break;
}
for (i = d; i; i--) out[ye++] = temp[i];
out[ye++] = 10;
}
inline void print(){
fwrite(out, 1, ye, stdout);
} }
struct query{
int l, r, d, i;
inline query() {}
inline query(int a, int b, int c){
i = c;
l = a, r = b, d = l / block_size;
}
inline bool operator < (const query& other) const{
if (d != other.d) return (d < other.d);
return ((d & 1) ? (r < other.r) : (r > other.r));
} } Q[MAXQ];
void compress(int n, int* in, int* out){
unordered_map <int, int> mp;
for (int i = 0; i < n; i++) out[i] = mp.emplace(in[i], mp.size()).first->second; }
inline void insert(int i){
res += (long long)val[i] * (1 + 2 * freq[ar[i]]++); }
inline void erase(int i){
res -= (long long)val[i] * (1 + 2 * --freq[ar[i]]); }
inline void run(){
sort(Q, Q + q);
int i, l, r, a = 0, b = 0;
for (res = 0, i = 0; i < q; i++){
l = Q[i].l, r = Q[i].r;
while (a > l) insert(--a);
while (b <= r) insert(b++);
while (a < l) erase(a++);
while (b > (r + 1)) erase(--b);
out[Q[i].i] = res;
}
for (i = 0; i < q; i++) fastio::convert(out[i]); }
int main(){
fastio::init();
int n, i, j, k, a, b;
n = fastio::number();
q = fastio::number();
for (i = 0; i < n; i++) val[i] = fastio::number();
compress(n, val, ar);
for (i = 0; i < q; i++){
a = fastio::number();
b = fastio::number();
Q[i] = query(a - 1, b - 1, i);
}
run();
fastio::print();
return 0; }
答案 0 :(得分:3)
此解决方案http://codeforces.com/contest/86/submission/22526466(624毫秒,32 MB RAM使用)使用单个fread和手动解析内存中的数字(因此它使用更多内存);许多其他解决方案速度较慢,使用scanf
(http://codeforces.com/contest/86/submission/27561563 1620 ms 9MB)或C ++ iostream cin
(http://codeforces.com/contest/86/submission/27558562 3118 ms,15 MB)。并非所有解决方案的差异都来自输入输出和解析(解决方法方法也存在差异),但有些是。
fread(str, 1, 8333667, stdin);
此代码使用单fread
libcall读取最多8MB,这是完整文件。该文件最多可包含2(n,t)+ 200000(a_i)+ 2 * 200000(l,r)6/7位数字,带或不带换行符或由一个(?)空格分隔,因此大约8个字符数字最大值(数字为6或7,允许1000000,1个空格或\n
);最大输入文件大小类似于0.6 M * 8字节= ~5 MB。
inline int number(){
int i, j, val = 0;
while (str[ptr] < 45 || str[ptr] > 57) ptr++;
while (str[ptr] > 47 && str[ptr] < 58) val = (val * 10) + (str[ptr++] - 48);
return val;
}
然后代码使用解析十进制int数字的手动代码。根据ascii表,48 {57的http://www.asciitable.com/十进制代码是十进制数字(第二次循环):'0'...'9'
,我们可以从字母代码中减去48得到数字;将部分读取val
乘以10并添加当前数字。第一个while循环中的chr<45 || chr > 57
听起来像是从输入中跳过非数字。这是不正确的,因为此代码不会解析代码45,46,47 = '-', '.', '/'
,并且在读取这些字符后没有任何数字。
n = fastio::number();
q = fastio::number();
for (i = 0; i < n; i++) val[i] = fastio::number();
for (i = 0; i < q; i++){
a = fastio::number();
b = fastio::number();
实际阅读使用此fastio::number()
方法;和其他解决方案使用循环中调用scanf
或iostream operator <<
:
for (int i = 0; i < N; i++) {
scanf("%d", &(arr[i]));
add(arr[i]);
}
或
for (int i = 1; i <= n; ++i)
cin >> a[i];
这两种方法都更通用,但它们会进行库调用,它会从内部缓冲区读取一些字符(如4KB)或调用OS系统调用来进行缓冲区重新填充,并且每个函数都会执行许多检查并报告错误:对于每个数字输入scanf将重新分析相同的format string of first argument,并将完成POSIX http://pubs.opengroup.org/onlinepubs/7908799/xsh/fscanf.html中描述的所有逻辑以及所有错误检查。 C ++ iostream没有格式字符串,但它更具通用性:https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/istream.tcc#L156'operator>>(int& __n)
'。
因此,标准库函数内部逻辑更多,调用更多,分支更多;它们更普遍,更安全,应该用于现实世界的编程。这个“体育节目”比赛允许用户使用足够快的标准库函数来解决任务,如果你能想象算法的话。作者或任务需要编写具有标准i / o函数的多个解决方案,以检查任务的时间限制是否正确并且任务可以解决。 (对于i / o,TopCoder系统更好,你不会实现i / o,数据已经在某些语言结构/集合中传递给你的函数)。
有时sport programming中的任务对内存有严格限制:输入文件比允许的内存使用量大几倍,程序员无法将整个文件读入内存。例如:从输入文件中获取20万个单个非常长的数字,并加1,内存限制为2 MB;你不能正向读取文件中的完整输入数字;在向后方向上正确读取是非常困难的;你只需要忘记标准的加法方法(柱状加法)并用状态构建FSM(有限状态机),计算9
s的序列。