1> I/O效率问题
一篇文章中指出——getchar()/putchar()快于scanf/printf快于cin/cout
有些题目数据可能非常多,但是对数据的操作可能却相对简单,这时候不要因为I/O导致TLE,我想,几乎所有人都遇到过cin/cout换scanf/printf才能过的情形。
另外就是对于整型,可能手动解析是最快的(我还没试验,不能下定论)。因为scanf/sscanf/fscanf都是支持多种格式,所以实现上不可避免要各种判断。
最近做的一道题就是这样,用cin/cout超时,用scanf/printf大约0.7s,用自己手动解析的方式0.14s。
题目大致是先输入n(n<10^6),后面跟n行数据,每行都是整数。然后输出行数不定(和输入有关),也可以认为是和n同一个数量级。我最后的写法是:
// 这是手动解析int和输出int #define PARSE_INT( x ) do{ \ x = 0; \ int sgn = 1; \ while( *ptr < '0' || *ptr > '9' ) { if( *ptr == '-' ) sgn = -1; ++ptr; } \ while( *ptr >= '0' && *ptr <= '9' ) { x = x*10 + *ptr - '0'; ++ptr; } \ x = x * sgn; \ }while(0) #define OUTPUT( x ) do { \ int x0 = x; \ char num[32], *digit_pos = num + 31; \ num[31] = '\n'; \ while( x0 > 0 ) { \ *--digit_pos = x0 % 10 + '0'; \ x0 /= 10; \ } \ int sz = num + 32 - digit_pos; \ memcpy( optr, digit_pos, sz ); \ optr += sz; \ }while(0) // 这是输入输出缓冲区,确保足够大 char buff[MAXN*12]; char obuff[MAXN*12]; …… // 一口气将所有输入全部读入缓冲区 n = fread( buff, 1, sizeof( buff ), stdin ); PARSE_INT( n ); while( n-- ) { PARSE_INT( x ); ..... OUTPUT( y ); } // 一口气将所有输出 fwrite( obuff, 1, optr - obuff, stdout );
何谓two pointers?很多题目都是这个解题模式——先对数据排序,然后用两个指针遍历一遍数组,两个指针随着一定的限制条件向后或向前跳跃。
例如最近做的一道题,一个升序数组,当两个数之间的差恰好小于某个阈值,则进行一些计算,这时应该是两个指针依次向后走,他们之间的间距时大时小。
我的一个实现是:
for( int i = 0, j = 1; i < n; ++i ) { while( j < n && a[j] - a[i] <= threshold ) ++j; do_sth( i, j - 1 ); }然后看到另一个人的实现是:
for( int i = 0, j = 1; j < n; ++j ) { while( a[j] - a[i] > threshold ) ++i; do_sth( i, j ); }这两种实现对比一下,不难发现,我之前的实现是从前往后推,很有可能会推出界,所以要多个判断,而后面的实现是从后往前拉,有后面的指针作为天然的哨兵,不用担心越界。