關於快讀


關於快讀

普通的快讀大家應該都會寫, 我就不再贅述, 這里講一下用fread的快讀。

fread

首先函數原型

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

函數freadstream流中讀取nmemb個長度為size字節大小的數據,並將它們存儲在ptr給定的位置, 返回讀取的字節數。

比如fread(buf, 1, 10, stdin);就是從標准輸入流中讀取101字節大小的字符, 存在buf數組里。

因為它是一下子讀一大堆, 所以比較快, 那么怎么使用呢?

使用

首先定義一個字符數組, 大小為\(2^{20}\) (1 mb), 作為緩存, 每次讀取1 mb數據存在數組里, 讀數字的時候掃描數組, 像普通快讀一樣轉成數字, 讀完緩存就再讀 1 mb。

char buf[1<<20], *p1, *p2; //buf 緩存, p1 為指向緩存開頭的指針, p2 為指向緩存結束的指針
char gc() { 
    if (p1 == p2) { // 判斷是否第一次執行或讀取完緩存
        p1 = buf; // 重置開頭指針
        p2 = buf + fread(buf, 1, 1<<20, stdin); //讀取數據, 重置結尾指針
        if (p1 == p2) return EOF;
    }
    return *p1++; // 返回第一個字符並指針后移
}
inline int read() { //普通的快讀
    int f = 1, x = 0;
    char c = gc();
	while (c < '0' || c > '9') {
	    if (c == '-') f = -1;
	    c = gc();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc();
	return f * x;
}

去注釋, 壓行版本

char buf[1<<20], *p1, *p2;
char gc() { return p1 == p2 ? p2 = buf + fread(p1 = buf, 1, 1<<20, stdin), (p1 == p2) ? EOF : *p1++ : *p1++; }
inline int read(int f = 1, char c = gc(), int x = 0) {
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = gc();
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc();
	return f * x;
}

宏函數版本

char buf[1<<20],*p1,*p2;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({\
    int x = 0, f = 1;\
    char c = gc();\
    while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = gc();\
    while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc();\
    f * x;\
})

宏函數一定會內聯, 比如以下代碼

#include <cstdio>
char buf[1<<20],*p1,*p2;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({\
    int x = 0, f = 1;\
    char c = gc();\
    while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = gc();\
    while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc();\
    f * x;\
})
int a[100];
int main() {
    int n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = read();
}

就會展開為

#include <cstdio>
char buf[1<<20],*p1,*p2;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({\
    int x = 0, f = 1;\
    char c = gc();\
    while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = gc();\
    while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc();\
    f * x;\
})
int a[100];
int main() {
    int n = ({ int x = 0, f = 1; char c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); f * x;}), m = ({ int x = 0, f = 1; char c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); f * x;});
    for (int i = 1; i <= n; i++) a[i] = ({ int x = 0, f = 1; char c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? (-1) : *p1++) : *p1++); f * x;});
}

其他要注意的

  1. 調試的時候, 輸入完成后請手動輸入EOF(linux上為ctrl + d, windows上為ctrl + z)。

  2. 使用此快讀請不要使用其他輸入方式, 否則會因為緩存問題產生錯誤。

讀入速度比較

測試題目 P3865 【模板】ST表, 均未開啟O2優化

使用cinprintf

使用scanfprintf

使用getchar版本快讀和printf

使用fread版本快讀和printf


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM