關於快讀
普通的快讀大家應該都會寫, 我就不再贅述, 這里講一下用fread的快讀。
fread
首先函數原型
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
函數fread從stream流中讀取nmemb個長度為size字節大小的數據,並將它們存儲在ptr給定的位置, 返回讀取的字節數。
比如fread(buf, 1, 10, stdin);就是從標准輸入流中讀取10個1字節大小的字符, 存在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;});
}
其他要注意的
-
調試的時候, 輸入完成后請手動輸入EOF(linux上為ctrl + d, windows上為ctrl + z)。
-
使用此快讀請不要使用其他輸入方式, 否則會因為緩存問題產生錯誤。
讀入速度比較
測試題目 P3865 【模板】ST表, 均未開啟O2優化
使用cin和printf

使用scanf和printf

使用getchar版本快讀和printf

使用fread版本快讀和printf

