Loading

Antibiotic's NOTES

1.数组的初始化

int m;
cin>>m;
int a[m];//会导致错误(静态)
int a[100]={-1}//会变成这样:{-1,146,-126,534...}(只初始化了第一个数,其他会随机分配)
memset(a,0,100,sizeof(a));//可以把快速全部设成0(0换成-1也可以)❗换成1不行,不会设成1❌
bool b[100];
memset(b,0,sizeof(b));//全部设成0
memset(b,1,sizeof(b));//可以全部设成1✅
memset(b,-1,sizeof(b));//不会设成-1,而是255

注:memset的数据均使用Ubuntu下的g++命令测试(这玩意好像在不同的操作系统,不同编译器下的结果不同)

2.不定长度数字的读入

cin遇到换行不会停止,除非输入了其他类型

或者遇到了文件结束符EOF(在Windows下是Ctrl+Z,在Unix是Ctrl+D)

//BUG
int num,nums[10],i=0;
while (~scanf()) { //不会停止,除非有字符串
    nums[i]=num;
    i++;
}

补充:scanf的一些用法

  • scanf("%[^\n]",s);遇到换行符时才停止读入(这指的是一次读入,作为字符串)

    scanf()中[]里面^后面就是你要停止读入的字符,如把\n换成s意思就是遇到s就停止读入

    同时在^的后面可以放很多的字符,例如scanf("%[^sdf]",s);,意思就是遇到里面的任一个字符都停止读入。

  • while(scanf()!=EOF) 可以实现一直输入,一直到EOF(end of file,文件结束符),一般OJ的测评里输入的最后都会有这个

3.位运算

注意!位运算优先级别很低,会先计算 + -

//BUG
int i=3;
i=i<<3+i<<1;//在这里会先算3+i
//正确写法
int i=3;
i=(i<<3)+(i<<1);

4.关于输入输出的卡常

默认的时候,cin与stdin总是保持同步的,导致效率比较低

ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

只要加上这一行,cin可以达到scanf的速度(但是scanf好像更快一些),它可以禁用同步

不要用endl!!!特别慢!!!(cout << '\n')

注意:cin,cout不要与getchar,scanf,printf一起使用,同步流的过程会变得特别慢!!

5.getchar()的使用

getchar()会把换行符也当作一个字符,遇到换行,需要多写一个没用的getchar(),跳过换行符,就能继续读下一行了

6.务必检查数据的输入及初始化

7.sizeof()的使用

sizeof()是一个操作符(operator)

#include <stdio.h>
 
void main() {
    int a = 10;
    char b = 'b';
    short c = 2;
    long d = 9;
    float e = 6.29f;
    double f = 95.0629;
    int arr[] = { 1,2,3 };
    char str[] = "hello";
    double *p=&f;
    int *i=&a;
    //分别对各个变量使用sizeof运算
    printf("a=%d,b=%d,c=%d,d=%d,e=%d,f=%d,arr=%d,str=%d point_p=%d,point_i=%d\n",
           sizeof(a), sizeof(b), sizeof(c), sizeof(d), sizeof(e), sizeof(f),
           sizeof(arr), sizeof(str), sizeof(p), sizeof(i));
    system("pause");
}
//输出的结果是:a=4,b=1,c=2,d=4,e=4,f=8,arr=12,str=6 point_p=4,point_i=4

sizeof()实际上是获取了数据在内存中所占用的存储空间,以字节为单位来计数

sizeof()是在编译时确定大小的,而动态分配是运行过程中得到大小的

8.memset()的使用

memset函数是对字节为单位进行赋值的

void *memset(void *s, int ch, size_t n);

函数解释:将s中前n个字节用ch[1]替换并返回s。

其实这里面的ch就是ASCII为ch的字符(见附录);
将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII值

To continue:
sizeof()
memset()

9.自加++和自减--运算符

x++表示在使用x之后,使x的值加1,即x=x+1

++x表示使用x之前,先使x的值加1,即x=x+1

10.length()函数的返回值

string类size(), length()函数的返回值是无符号数

11.清空一个队列queue的几种方法

1

直接用空的队列赋值

queue <int> q1;
//process...
q1=queue <int> ();

2

遍历出队列

while(!Q.empty()) {
    Q.pop();
}

3

使用swap(),这种是最高效的,定义clear,保持STL容器的标准

void clear(queue <int> &q) {
    queue<int> empty;
    swap(empty, q);
}

12.sort()高级用法

降序以及自定排序

sort()默认是升序排列,可以用如下方法使它降序排列

int cmp(int a,int b) {
    return a>b;//降序排列,也可以实现其他的
}
int main() {
    int nums[5] = {4, 2, 3, 1, 5};
    sort(nums, nums+5, cmp);
    return 0;
}

对于结构体等复杂结构的另一种操作

该操作比较有意思,通过重载操作符实现

见LINK(记得测试一下)

13.贪心的证明

一种重要的证明方法:邻项交换法

只要计算假如相邻的两项交换位置,会对答案产生的影响,分析是交换更优还是不交换更优

14.秦九韶算法

也叫霍纳算法,用于快速计算多项式的值

一般地,一元n次多项式的求值需要经过\(\dfrac{(n+1)\times n}{2}\)次乘法和\(n\)次加法,而秦九韶算法只需要\(n\)次乘法和\(n\)次加法,在人工计算时,一次大大简化了运算过程

具体实现:

把一个n次多项式

\(f(x)=a_nx^n+a_{n-1}x^{n-1}+\cdots+a_1x+a_0\)

改写成如下形式:

\[\begin{aligned} f(x) &=a_nx^n+a_{n-1}x^{n-1}+\cdots+a_1x+a_0\\ &=(a_nx^{n-1}+a_{n-1}x^{n-2}+\cdots+a_2x+a_1)x+a_0\\ &=((a_nx^{n-2}+a_{n-1}x^{n-3}+\cdots+a_3x+a_2)x+a_1)x+a_0\\ &\vdots\\ &=(\dots((a_nx+a_{n-1})x+a_{n-2})x+\cdots+a_1)x+a_0 \end{aligned} \]

求多项式的值时,首先计算最内层括号内一次多项式的值,即

\[v_1=a_nx+a_{n-1} \]

然后由内向外逐层计算一次多项式的值,即

\[v_2=v_1x+a_{n-2}\\ v_3=v_2x+a_{n-3}\\ \vdots\\ v_n=v_{n-1}x+a_0 \]

这样,求\(n\)次多项式\(f(x)\)的值就转化为求\(n\)个一次多项式的值

结论:对于一个\(n\)次多项式,至多做\(n\)次乘法和\(n\)次加法

15.卡常技巧

减少取模运算

可以实现2s -> 500ms的优化

16.int main(int argc,char** argv)

argc是命令行总的参数个数

argv是命令行的每一个参数(字符数组)

char**相当于一个字符串数组

关于char**,见这篇博客

这个赋值的过程是编译器完成的,我们只需要读入数据即可

e.g.

~$ test
# 这里是 argc 是 1(包括了命令名)
~$ test myarg1 myarg2
# 这里是 argc 就会是 3(包括了命令名和两个参数)
# argv[0] 的值就是 "test",argv[1] 的值就是 myarg1,argv[2] 的值就是 myarg2

17. 关于<<

\(1<<n\)中,若\(n\)为long long,仍然无法进行long long的运算,会越界;所以,必须要把\(11\)变成ll1<<n

\(2\) 的整次幂可以直接用位移,别用pow()

18.一定要注意取模的数据范围,有可能超的一定要记得取模!!!

19.emplace() 和 insert()

用于向vector容器中插入元素,其中emplace_back对应push_back,emplace_front对应push_front,emplace对应的是insert(但是不能一次插入多个元素)

为什么要使用emplace()呢?

速度比insert快,简单来说,emplace()在插入元素时,是在容器的制定位置直接构造元素,而不是先生成,在复制(或移动)到容器中去,所以推荐用emplace()

insert()是 \(O(N)\) 的!

20.,运算符

,可以把多条语句写在一起,但是要注意,return的前后都不能有,!!

21.CE的奇妙原因

search这个函数是在c++17的std命名空间中的,如果在搜索题用了这个写,就会CE(在c++11,c++14里面都不会有问题)

p.s. 貌似ACwing的默认c++标准就是17或者20

numbers是c++20标准中的,定义于命名空间std::numbers,如果在洛谷手残点了c++20,数组名又用了numbers,就会CE

next和prev是c++保留字,index是Linux下的C函数,不能随便用

next -> nxt prev -> prv/pre index -> idx

22.关于printf()

printf()必须严格对应数据类型,否则会出大问题

int res = 5;
printf("%.2f", res); //会输出0.00,有问题
printf("%.2f", res*1.0); //这样就没有问题了

注意:在printf()`中没有lf这个格式符,float和double都是f

如下表,printf()中的格式控制

数据类型 格式符
int %d
long long %lld
float %f
double %f / %lf
char %c.
字符串(char数组) %s
long double %Lf.

long double输入也是%Lf

23.指针的大小

指针的大小是8个字节!!!!

是int的的两倍!!!!

24. lower_bound & upper_bound


附录

ASCII码表

![]( https://bkimg.cdn.bcebos.com/pic/e850352ac65c103880a07b53bc119313b17e8941?x-bce-process=image/watermark ,image_d2F0ZXIvYmFpa2UxMTY=,g_7,xp_5,yp_5)


  1. size_t是一个依赖于编译系统的值,一般定义为typedef unsigned int size_t ↩︎

posted @ 2022-11-10 21:44  Antibiotics  阅读(32)  评论(0)    收藏  举报