快读攻略(详)

· · 个人记录

读入、输出的时间也吃运行耗时。快读可以给算法部分节省时间,帮助暴力,或者占时间优势冲刺 rank1!

快读大概有多快……

读入方式 读入内容 平均耗时
C++ fread() 1~1000万整数排列 328.883ms
C++ 普通快读 1~1000万整数排列 894.201ms
C++ scanf() 1~1000万整数排列 1074.278ms

某 NOIlinux 测试,多于两千组,clock() 计时的,不加优化。

读入整数包括读取字符和计算、赋值给变量,因此 fread 省去读入时间的比例非常高。不过,scanf 灵活性好强……

快读不好写?

普通快读的原理和实现都很普通,嗯嗯。

而它可以用 fread 优化。别慌,fread 所做的事情,也就类似于

scanf("%s", a);

普通快读

知道就不用看了

原理

“如题面无特殊说明,输入文件格式如下:除两两相邻的元素之间均有单个空格符外,文件中将不会出现其他空格;包括最后一行数据在内,文件中的每一行末尾均有一个回车。”

实现

后面跟着解释

#include <cstdio>
#include <cctype>
inline int getint()
{
    int res = 0, neg = 0, ch = getchar();

    while(!(isdigit(ch) or ch == '-') and ch != EOF)
        ch = getchar();

    if(ch == '-')
        neg = 1, ch = getchar();

    while(isdigit(ch))
        res = res * 10 + (ch - '0'), ch = getchar();

    return neg ? -res : res;
}

普通快读,每次读一个整数。这个函数分成五个简单的部分:

说明

测试

语文成绩 2000万个两位数

HH的项链 150万个五位数

如何比这个读入更快?

begin
    read(n)
end.

用 fread 优化普通快读

就是优化 getchar()

语法

函数 fread() 在 <cstdio> 里。它能把数据读到你指定的位置。它做的只是把字符读进来……

这段代码以后字符数据都在 a 数组里了。所以 getchar 就不要了。

我们自己写一个函数来替代 getchar()。

实现

const int BUFSIZE = 1 << 20;//1048576

char tmp[BUFSIZE];
int cnt = 0, Max = 0;

inline char getch()
{
    if(cnt == Max)
    {
        cnt = 0;
        Max = fread(tmp, 1, BUFSIZE, stdin);
    }

    return tmp[cnt++];
}

下面是指针写法,推荐指针!

#include <cstdio>
#include <cctype>
const int BUFSIZE = 1 << 20;
char ibuf[BUFSIZE], *is = ibuf, *it = ibuf;
inline char getch(){
    if(is == it)
        it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin);
    return is == it ? EOF : *is++;
}
inline int getint(){
    int res = 0, neg = 0, ch = getch();
    while(!(isdigit(ch) or ch == '-') and ch != EOF)
        ch = getch();
    if(ch == '-')
        neg = 1, ch = getch();
    while(isdigit(ch))
        res = res * 10 + (ch - '0'), ch = getch();
    return neg ? -res : res;
}

说明

普通快输

快输出场率没有快读高的?

但还真有派上用场的时候……整数 fwrite() 还是有明显优化效果的。

输出方式 输出内容 平均耗时
C++ fwrite() 1~1000万整数排列 734.430ms
C++ printf() 1~1000万整数排列 1130.535ms
C++ 普通快输 1~1000万整数排列 1356.368ms

某 NOIlinux 测试,多于两千组,clock() 计时的,没加优化。

原理

“当同一行中有多于一个元素时,须用单个空格符以作分隔。”

代码

inline void putint(int res)
{
    char q[10];

    if(res == 0)
        putchar('0');
    else
    if(res < 0)
    {
        putchar('-');
        res = -res;
    }

    int top = 0;
    while(res)
    {
        q[top++] = res % 10 + '0';
        res /= 10;
    }

    while(top--)
        putchar(q[top]);
}

用 fwrite 优化普通快输

其实只优化了 putchar()

语法

fwrite() 也在 <cstdio> 里。它把数据输出到你指定的地方。它做的也只是把现成的字符一块一块输出去。

用自己写的函数代替 putchar()。

实现

const int BUFSIZE = 1 << 20;
char tmp[BUFSIZE];
int cnt = 0;

inline void flush()
{
    fwrite(tmp, 1, cnt, stdout);
    cnt = 0;
}

inline void putch(char ch)
{
    tmp[cnt++] = ch;
    if(cnt == BUFSIZE)
        flush();
}

输出的数字之间需要间隔符,可直接以这样的方式实现

for(int i = 1; i <= n; ++i)
    putint(a[i]), putch(' ');
putch('\n');

用 fwrite() 优化字符串输出也是很好的。

参考代码

剪贴板