学习使用cpp

看起来还是很有必要啊(

Posted by ShanLunjiaJian's Blog on March 13, 2022

一些标准库和语法的内容。

主要参考cppreference.com。


输入输出

如果你是c党,想要读入一行,可以使用fgets(char *str,int count,FILE *stream)这个函数,看起来用法可能是fgets(s,inf,stdin)这样的。

不过更好的方法是使用scanf("%[^\n]",s)这样的。来详细学习一下scanf()

scanf()的第一个参数称为格式字符串,它用来匹配输入的串。格式串中每个需要被输入的东西用一个%...这样的表示,比如我们经常会用到%d %f %c %s这样的。不需要被输入的东西会被匹配之后扔掉,比如我写scnaf("qwq%dqwq",&x),输入qwq114514qwq,得到x是114514。如果你想要扔掉%这个字符,使用%%。如果你写了一个空白字符,那么scanf()会匹配极长连续空白字符,如果你写了两个也是一样的。写空格,换行和tab是没有区别的。

%后面跟的东西有很多种,这称为转换规范。按写的顺序给出一般情况下可能用到的 :

  • 赋值抑制字符*,表示不会把这个结果赋值给任何参数。

  • 一个数表示最大读取长度。对于会跳过空白字符的转换格式说明符,它不计算这些空白字符。

  • 表示参数类型的长度修饰符,比如llL这样的。

  • 转换格式说明符。

    • d匹配十进制整数,u匹配无符号十进制整数,o匹配八进制整数,x匹配十六进制整数。可以被hh(char, 1 byte),h(short, 2 bytes),l(long, 4 bytes),ll(long long, 8 bytes)修饰。所以cf的I64是什么鬼东西?

    • f匹配一个浮点数,可以被l(double, 8 bytes),L(long double, 12 bytes)修饰。

    • s匹配一个不包含空白字符的字符串。

    • [S]匹配集合S中的字符组成的字符串,这个集合可以包含空白字符。集合类似于正则的写法,也就是把一堆摞起来,在一开始可以加一个^表示补集。但是不一定可以使用a-z这样的表示,不过我感觉主流编译器应该都可以,不过还是不要轻易在正式比赛中尝试。

    • c一般被用来匹配一个字符,请注意这个字符可以是空白字符。请注意它不会在读入的最后写一个\0进去。看起来可以被[S]代替。

请注意使用%s和%[S]读取字符串的时候,最后必须留一位,因为scanf总是会在串后面放一个空字符。我一般读串会留十位(

printf()是类似的。特别地,%后面依次可以选择使用这些符号

  • 负号-表示在域中左对齐。关于域是什么,就是这个%…所输出的那一段。

  • 加号+表示对于有符号数,始终输出它的符号,而不是在它是负数的时候才输出。

  • 空格 表示对于有符号数,如果它是正数,在符号位输出空格。

  • 井号#表示对于八进制输出前导0,十六进制输出0x,浮点数总是输出小数点,除此之外是ub。好像没什么用。

  • 0表示对于整数和浮点数,用前导零代替空格来填充域。

  • 一个数或者星号*指示最小域宽,也就是输出的最小长度,如果不满默认用空格填充在前面,可以被负号或者0改变。使用星号表示用一个额外参数指示。

  • .后面一个整数或星号*表示精度,对于整数这个是长度。使用星号表示用一个额外参数指示。

  • 表示参数类型的长度修饰符。

  • 转换格式说明符。与scanf()相比,多了e表示科学计数法,a表示十六进制浮点数。

sscanf()sprintf()可以把东西从一个char*里面读出来或者写进去。fscanf()fprintf()可以读文件指针,比较常见的是用来输出调试语句,使用fprintf(stderr,"Debug: %d",x)这样的。


算法库

c是有排序算法的/jy,但是好像没有复杂度保证。它叫qsort(),在<stdlib.h>中。

inplace_merge()实现了归并排序一层的过程,而stable_partation()实现了快速排序一层的过程,不过看起来后者没有啥用,因为我们有nth_element()


数值库

valarray<T>来自<valarray>,实现了一个类型T的定长数组,可以方便地实现点对点的操作。当然很多时候会选择手写这种。

isinf()isnan()isfinite()来自<math.h>,可以检查一个数是不是inf,是不是nan,是不是inf和nan之外的数。

我平时使用xorshift生成随机数。如果要塞进shuffle()里面,可以用mt19937 r(random_device{}())这样的。


容器库

vector.reserve()用来申请空间。vector.clear()不会释放空间,如果要释放空间地clear,可以使用vector<>().swap(v)这样的;如果要缩小空间,可以使用vector.shrink_to_fit()

使用vector.data()可以得到vector底层的数组。


pbds

可以这样定义顺序统计树 :

1
2
3
4
5
6
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;

typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ordered_set;

然后用ordered_set.find_by_order()查询kth,ordered_set.order_of_key()查询rank。

rope不是很好用。pbds的堆用于优化dij必然完全没有我的基数堆快,可并堆的话左偏树/配对堆也不难写。hash table容易手写。只有平衡树难写了!我去,是不是写一万个平衡树题就可以抛弃pbds了(


lambda表达式

[捕获](参数)修饰符{函数体}。捕获是以逗号分隔的列表,用于使用lambda表达式声明处的局部变量,每一项可以是&a =a this这样的,&a表示可以使用局部变量a的引用,=a表示使用copy,如果只写& =不写a则表示对所有变量。this表示可以使用所在类的成员。如果留空则表示不捕获任何变量。参数就是参数。修饰符有multable,表示如果以copy捕获了一个变量,可以修改它的值(而对外面没有影响)。