奇技淫巧 NOIP的讀入優化

2022-05-10 22:45:09 字數 2677 閱讀 3377

最近看到洛谷上面有乙個讀入優化的**:

inline char get_char()

inline

short

read()

說實話第乙個函式get_char的第二行,這麼長一六三目運算子真心看不懂

(下面的read函式裡面那個isspace()和isdigit()就是判斷這個字元是不是空格,是不是數字,是的就返回true,不是返回false。你看多沒用的函式= =)

inline char nc(void)  

return *p1++;

}

於是研究了一會,發現這是乙個極其神奇的讀入優化

一般來說我們讀入都用的scanf和cin,實在必要的時候可以用getchar讀入優化。

然後眾所周知,cin比scanf慢,getchar最快。

但是到底差距有多大很多人都不知道。

於是上個星期我做了乙個賊有意思的測試,把scanf、cin、getchar(分為巨集定義函式和內聯函式兩個)分別讀入1000000個數,然後輸出執行時間。

getchar的兩個函式貼在這裡:

#define gi(a) do 

while(0

)inline

void gi2(int &a)

//(僅限正整數)

發現scanf大概比cin快2倍,getchar比cin快5倍。

其中巨集定義的getchar稍稍比內聯的getchar快那麼一點點點點。

然後就是今天我看到的玄學優化了。

這裡有所有讀入的速度評估(看來我還不是第乙個幹這種賊有意思的事情的wwww)

經過實測,這種優化比scanf快了10倍!

函式原型是這樣的:

size_t fread ( void *buffer, size_t size, size_t count, file *stream) ;
可以看到有四個引數,分別是讀入的陣列,讀入每個資料項的位元組數,讀入的個數,以及讀入的檔案stream。

返回的是讀到的資料項的個數。

此外還有個static關鍵字,就把它看成是函式裡面的全域性變數就行了,也就是說再用一次這個函式,裡面的值不會變的。

此外static只有在第一次定義的時候才能賦值,之後呼叫的時候賦值是無效的,也就是說之後的呼叫函式這個賦值那一行是沒用的。

這裡還有個點,看這一行:

p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);
這裡的=號的返回值就是賦值號右邊的那個值,也就是buf的值。

那麼就等於寫成這樣:

p1 =buf; 

p2 = buf+ fread(buf, 1, 100000, stdin);

在我們一開始呼叫函式的時候,p1 p2都被賦值為buf的陣列開始的位置,之後進入if語句,p2變成資料最後的位置(開始的位置+資料的長度 = 最後的位置)。

然後隨著每次返回,p1都會往前面移動乙個,直到p1也遍歷到了最後的位置,p1 == p2

這時候再次進入if語句,然後同樣p2變成資料最後的位置,因為p1這時也是資料最後的位置了,所以p1照樣==p2,於是資料遍歷結束了,返回檔案結束符eof.

就這樣,完美模擬一次檔案讀寫~

然後把if語句簡化就變成了那個很長一六的三目運算子:

inline char get_char()
可以把這個模板背一下,然後就直接套自己的getchar讀入優化模板了。

當然也可以把這裡面的static索性全部拿到外面去,變成全域性變數,然後做乙個巨集定義:

char buf[1000001],*p1=buf,*p2=buf;

#define get_char() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?eof:*p1++)

雖說這樣肯定比內聯函式快,但是因為巨集定義畢竟是機械式替換的……所以不保證不出玄學bug,慎用。(不過一般來說用我自己寫的模板不會有問題)

(其實我不會把只有一行語句的巨集用do while(0)封裝起來,所以只能打個括號完事)

這個優化雖然快是快,但是因為奇技淫巧……不保證不出bug,所以還是謹慎使用。

就當做普及乙個玄學優化吧。

這裡有乙個大神寫的整合版,大致原理是一樣的,不過**更簡單,而且讀入比我的又要快一倍(用的指標+一次性讀入所有的整數),**如下

const

int maxs = 60*1024*1024

;const

int maxn = 10000000

;char

buf[maxs];

intnumbers[maxn];

void analyse(char *buf,int len =maxs)

void

fread_analyse()

最後貼上我把這個玄學優化寫進我的玄學getchar裡面弄出的超級巨型玄學賊有意思奇技淫巧讀入優化

char buf[1000001],*p1=buf,*p2=buf;

#define get_char() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?eof:*p1++)

#define gi(a) do

while(0)

git 奇技淫巧

例如 1.0.0 git tag a 1.0.0 m 1.0.0 版本的備註資訊.複製 git push origin tags 複製 例如 1.0.0 git tag d 1.0.0 複製 刪除遠端標籤需要先刪除本地標籤,再執行下面的命令 git push origin refs tags 1.0...

Noip前的大抱佛腳 奇技淫巧

set查詢前驅後繼multiset iterator iter s.insert x iter s.find x 返回迭代器 iter 前驅 int ans iter s.erase find x return ans 或者可以使用 lower bound 大於等於 upper bound 嚴格大於...

c 的奇技淫巧

關於陣列 數論演算法技巧 stl其他 while scanf d d n,m eof 等價於 while scanf d d n,m 2 前者eof為檔案結束符,較保險 後者 後的數字為輸入的變數的個數 不能只寫while scanf d d n,m 這樣無法結束讀入 wwq大佬教的,希望我不要和他...