淺談超快讀


inline int read() {
	int x = 0;
	char c = getchar();
	for (; c < '0' || c > '9'; c = getchar());
	for (; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + (c ^ 48), c = getchar());
	return x;
}

這是一個我們平常使用的快讀,他也能幾乎達到所有題目的要求。但是有一些題目,比如沒有加單調隊列的跳房子,在我校機房的土豆評測機上經常會被卡掉一個點,而且時間就差一點,於是超快讀就進入了我的必備模板。


我們知道,getchar是每次讀出一個字符,若是我們能一次性讀進一大串字符,那樣效率就會快很多。
cstdio里有一個fread函數正好能滿足我們的需要。這個函數的原型是這樣的:

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

看不懂沒關系,我們慢慢解釋。第一個形參為讀入數據存放的位置,我們一般用數組指針傳入;第二個形參為每個數據的長度,單位是字節,如char就是1;第三個形參是理想情況(輸入數據量充足)下最多讀入多少個數據;第四個形參是讀入數據的位置,也就是指定輸入流,通常為stdin。這個函數的返回值為實際讀入數據的個數。
那么,稍稍改進一下我們的getchar吧。

char buf[1 << 20], *_now = buf, *_end = buf;
//buf是緩沖數組,就是讀入的一串數據存放的地方;_now是字符指針,指向當前想取的那個字符;_end也是字符指針,指向這一串字符的最后一個。
inline char getchar() {
	if (_now == _end) {//如果這一串數據處理完了
		_end = _now = buf;
		_end += fread(buf, 1, 1 << 20, stdin);//那就再讀一串,注意指針要回歸原位
		if(_now == _end) {//如果沒有讀進來,就說明沒有數據了
			return EOF;
		}
	}
	return *_now++;
}

把這個加到快讀的前面就成超快讀了,當然getchar的命名要改一下。


你可能會說,我的快讀已經很長了,再加上這一段,豈不是……
沒事,接下來我們來壓下代碼,需要用到,&&兩個運算符。

首先是,運算符,這個我們一般在寫條件時用到,用,並列的語句,判斷真假時只取最后一個。

for (int i = 1; i <= 10, i <= 14, i <= 6; ++i)
	cout << i << endl;

輸出是:

1
2
3
4
5
6

其次是&&運算符,這里有一個短路求值的概念,即當且僅當左側運算對象無法確定表達式的結果時才會計算右側運算對象的值。

int a = 0;
if(10 > 20 && (a += 1, 1));//后半句沒有參與表達式的運算
if(10 < 20 && (a += 2, 1));//后半句參與了表達式的運算
cout << a << endl;

輸出為:

2

所以代碼就壓成了:

char buf[1 << 20], *_now = buf, *_end = buf;
inline char _getchar() {
	return _now == _end && (_end = (_now = buf) + fread(buf, 1, 1 << 20, stdin), _now == _end) ? EOF : *_now++;
}

當然你也可以使用宏定義,這樣就不用改getchar的命名了。

char buf[1 << 20], *_now = buf, *_end = buf;
#define getchar() (_now == _end && (_end = (_now = buf) + fread(buf, 1, 1 << 20, stdin), _now == _end) ? EOF : *_now++)

寫在最后:

  • 此快讀一般用於文件讀寫。
  • buf數組開小了會影響速度(會讀很多次),開大了會MLE,所以請根據題目和輸入數據范圍隨機應變,一般 \(2^{20}\)\(2^{23}\) 為適。
  • 附一張讀入十萬隨機數據的速度:
輸入方式 cin scanf cin(解綁) 快讀 超快讀(buf[1<<2] 超快讀(buf[1<<20]
速度/ms 140 110 23 34 15 5
參考文獻:
[http://www.cplusplus.com/reference/cstdio/fread/](fread - C++ Reference)
[https://docs.microsoft.com/en-us/previous-versions/jj987785(v=vs.140)](operator&& Operator (C++ REST SDK))


免責聲明!

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



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