C ++:竞争性编程技巧的说明

时间:2018-07-12 04:17:08

标签: c++ optimization

在用于竞争性编程的DMOJ在线判断器上,如果问题仅要求读取未签名的整数数据类型,则在执行时间(C ++)上更快的提示之一是在顶部添加此宏。

这是如何工作的,使用它的优缺点是什么?

#define scan(x) do{while((x=getchar())<'0'); for(x-='0'; '0'<=(_=getchar()); x= (x<<3)+(x<<1)+_-'0');}while(0)
char _;

来源:https://dmoj.ca/tips/#cpp-io

2 个答案:

答案 0 :(得分:5)

首先让我们重新格式化一下:

#define scan(dest) \
  do { \
    while((dest = getchar()) < '0'); \
    for(dest -= '0'; '0' <= (temp = getchar()); dest = (dest<<3) + (dest<<1) + temp - '0');
  } while(0)
char temp;

首先,外部do{...}while(0)只是为了确保正确解析宏。有关更多信息,请参见here

接下来,while((dest = getchar()) < '0');-可能只是dest = getchar(),但是它通过丢弃'0'字符以下(但不是上方)的任何字符来做一些额外的工作。这很有用,因为空格字符都“小于” ascii中的0字符。

宏的实质是for循环。首先,初始化表达式dest -= '0'通过利用ascii编码中的0-9字符是相邻且顺序的事实,将dest设置为该字符表示的实际整数值。因此,如果第一个字符为'5'(值53),则减去'0'(值48)将得到整数值5

条件语句'0' <= (temp = getchar())做几件事-首先,它获取下一个字符并将其分配给temp,然后检查其是否大于或等于{{1 }}字符(因此在空白处将失败)。

只要字符是数字(或至少等于'0'),就对增量表达式进行求值。 '0'-dest = (dest<<3) + (dest<<1) + temp - '0'表达式从ascii到数值进行与以前相同的调整,并且移位和加法只是乘以10的一种晦涩的方式。换句话说,它等效于{{ 1}}。乘以10并加上下一位数字的值就是最终值。

最后,temp - '0'声明临时字符存储,以供程序中的后续宏调用使用。

至于为什么要使用它,我怀疑与temp -= '0'; dest = dest * 10 + temp;char temp;之类的东西相比,它会提供任何可衡量的收益。

答案 1 :(得分:1)

它的作用是通过一系列过早的优化逐个字符地读取数字。有关更多详细信息,请参见@MooseBoys的答案。

关于它的优缺点,我完全看不到使用它的任何好处。像(x<<3)+(x<<1)这样等于x * 10的东西是应该由编译器而不是您自己完成的优化。

据我所知,cincout足够快用于所有竞争性编程目的,尤其是在禁用与stdio同步的情况下。自从开始竞争性编程以来,我一直在使用它,从来没有任何问题。

此外,尽管人们普遍认为,我自己的测试表明cincout的运行速度并不比C I / O慢。您可以尝试自己测试其性能。确保已启用优化。

显然,当他们的算法最重要时,一些有竞争力的程序员会将过多的精力放在快速I / O之类的东西上。