2022暑假ACM集训周记(持续更新~)
2022暑假ACM集训周记
Week1
Day1
C++头文件
#include<bits/stdc++.h> //万能头文件
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include <iostream> // 引入流输入输出库
using namespace std;
cin>>n; //cin输入
cout<<n<<endl; //cout输出,endl换行
不定量输入
while(~scanf("%d",&a)); //ctrl-z结束输入
while(scanf("%d",&a)!=EOF);
while(scanf("%d",&a)!=-1);
while(scanf("%d",&a)!=2;
//读取n输入
scanf("%d",&n);
while(n--);
//0结束
while(scanf("%d",&n)&&(a));
浮点数陷阱
#include<stdio.h>
int main()
{
doublei;
for(i=0;i!=10;i+=0.1)
printf("%.1lf\n",i);
return 0;
}
/*说明:对于i可以达到10.0,但永远不会与10相等,所以for循环是一个死循环。
对于float和dobule类型的数据不能直接用==和!=来比较大小,即不要测试精确的浮
点型数值,需要用精度比较,来测试一个可接受的数值范围。如:*/
//for(i=0;fabs(10-i)>1e-5;i+=0.1)
OJ各类错误提示
Accepted 通过
Presentation Error 输出格式错误。
Wrong Answer 答案错误。
Runtime Error 程序运行时发生错误,多为数组访问越界。
Time Limit Exceeded 超内存错误,程序运行使用的内存超过限制的内存用量。
Compile Error 编译错误,源代码中有语法错误。
Day2
memcpy函数
void *memcpy(void *dest, void *src, unsigned int count);
使用memcpy函数要包含头文件string.h
从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
e.g.
//从数组a复制k个元素到数组b(int)
memcpy(b,a,sizeof(int)*k);
//浮点(double)
memcpy(b,a,sizeof(double)*k);
//把数组a全部复制到数组b中
memcpy(b,a,sizeof(a));
memset函数
void *memset(void *buffer,char c,int count);
把buffer所指内存区域的前count个字节设置成字符c,第三个参数指的是字节的个数,返回指向buffer的指针
e.g.
memset(a,0,sizeof(a)) //把a数组的所有字节赋为0,比for方便
正确使用memset - 王陸 - 博客园 (cnblogs.com)
getchar()介绍
int getchar(void);
getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1
可以利用getchar()函数让程序调试运行结束后等待编程者按下键盘才返回编辑界面
用法:在主函数结尾return 0之前加上getchar()
#include <stdio.h>
int main(void)
{
for(int i=1;i<=10;i++)
printf("%d ",i);
getchar(); //用以暂停程序
return 0;
}
gets()
char *gets(char *buffer);
从stdio流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中
换行符不作为读取串的内容,读取的换行符被转换为null值,并由此来结束字符串
返回值:
- 读入成功,返回与参数buffer相同的指针;读入过程中遇到EOF(End-of-File)或发生错误,返回NULL指针
- 所以在遇到返回值为NULL的情况,要用ferror或feof函数检查是发生错误还是遇到EOF
注 意:
- 本函数可以无限读取,不会判断上限,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出
- 如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值
- 为了避免这种情况,我们可以用
fgets()来替换gets()
C语言中的gets(s)存在缓冲区溢出漏洞,不推荐使用
isupper()
extern int isupper(int c);
判断字符c是否为大写英文字母:小写return 0;
islower()
int islower(int c)
检查参数c是否为小写英文字母:小写return true;else return 0;
toupper()
extern int toupper(int c);
将字符c转换为大写英文字母:返回大写字母
tolower()
extern int tolower(int c);
将字符c转换为小写英文字母:返回小写字母
指针
void my_swap(int &a, int &b) // 和指针等价实现的交换函数
{
int t = a;
a = b;
b = t;
}
Day3
hypot()
double hypot(double x, double y);
可以求三角形的斜边长
assert()
#include<assert.h> //head
ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式。
- 如果表达式为 FALSE (0), 程序将报告错误,调用库函数abort()并终止执行。
- 如果表达式不为 0,则继续执行后面的语句。
- 这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。
作用域和生存期
作用域
- 变量的作用范围(全局变量和局部变量)
生存期
- 变量从被生成到被撤消的这段时间,即变量占用内存的时间。
递归调用
递归计算n!
int fac(int n){
if(n==1)return 1;
return fac(n-1)*n;
}
求组合数(高效递归版)

函数原型
double Cmb(int x, int y);
说明:x 和 y 为非负整数,且 x ≥ y ≥ 0,函数值为组合数 Cxy。
要求:不要使用循环语句,不调用阶乘函数和排列数函数。找出最快的递推公式,该函数直接调用自己求得结果。
#include <stdio.h>
double Cmb(int x, int y);
int main()
{
int m, n;
scanf("%d%d", &m, &n);
printf("%.10g\n", Cmb(m, n));
return 0;
}
/* 你提交的代码将被嵌在这里 */
| 输入样例 | 输出样例 |
|---|---|
| 0 0 | 1 |
| 5 0 | 1 |
| 34 17 | 2333606220 |
| 160 158 | 12720 |
| 1000 100 | 6.385051193e+139 |
source code
double Cmb(int x, int y){
if(x-y<y)
y=x-y;
if(x==y||y==0)
return 1;
return x*1.0/y*Cmb(x-1,y-1);
}
bool函数
bool n=true;
bool m=false;
//n=1,m=0;
bool flag=1>2;
//1>2为假(0),所以flag=0;
bool temp=2>1;
//2>1为真(!0),所以temp=1;
Day4
复杂度
STL分为三类
- 容器(container)
- 算法(algorithm)
- 迭代器(iterator)
Day5
STL container(容器)
<vector>
<list>
<deque>
<set>
<stack>
<queue>
<map>
<unordered_map>
queue
#include<queue>
//queue<Type,Container>
queue<int>q1;
queue<double>q2;
queue<char>q3;
//默认为用deque容器实现的queue;
queue<char,list<char>>q1;
//用list容器实现的queue;
queue<int, deque<int>>q2;
//用deque容器实现的queue
stack
#include<stack>
stack<int>q;
int x;
q.push(x); //x存入栈顶
q.top(); //返回栈顶元素
q.pop(); //删除栈顶元素
q.size(); //返回栈元素个数
q.empty(); //判断栈是否为空,空返回true,非空返回false
vector
<vector>
- 动态数组,运行时根据需要改变数组大小
- 以数组形式存储,内存空间是连续的,索引可以在常数时间内完成。
- 但是在中间进行插入和删除操作,会造成内存块的拷贝。
所谓动态增加大小,并不是在原空间之后接续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。因此,对vector的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。

#include<vector>
//定义具有10个整型元素的向量(尖括号为元素类型名,它可以是任何合法的数据类型),不具有初值,其值不确定
vector<int>a(10);
//定义具有10个整型元素的向量,且给出的每个元素初值为1
vector<int>a(10,1);
//用向量b给向量a赋值,a的值完全等价于b的值
vector<int>a(b);
//将向量b中从0-2(共三个)的元素赋值给a,a的类型为int型
vector<int>a(b.begin(),b.begin+3);
//从数组中获得初值
int b[7]={1,2,3,4,5,6,7};
vector<int> a(b,b+7);
//定义结构性数组
struct point {int x,y;};
vector<point>a; //a用来存坐标
//在向量尾部添加元素1
a.push_back(1);
//元素个数
a.size();
//判断是否为空
a.empty();
//删除尾部元素
a.pop_back();
//清空
a.clear();
//反转数组
reverse(a.begin(),a.end());
//删除元素1
a.erase(1);
//多维数组
vector<int>a[max];
//第一维大小是固定的MAXN,第二维是动态的
sort()
#include<algorithm>
const int N=1e5;
//O(nlogn)
void sort (RandomAccessIterator first, RandomAccessIterator last);
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
//排序范围[first,last)不包括last
int a[N];
bool cmp(int a,int b){
return a<b; //定义从大到小排序
}
sort(a,a+n); //默认从小到大排序a
sort(a,a+n,cmp) //自定义排序准则
string
#include<string>
string s; //创建对象
s="Hello" //赋值
string s1=s.length(); //获取字符串长度
string s1=s.size(); //获取字符串长度
string s3=s1+s2; //字符串连接
//查找串
//find-从指定位置起向后查找,直到串尾
//从第一个字符开始查找,返回首次匹配的位置
cout << s.find('e') << endl; //1 初始位置0
//从第3个字符开始查找
cout << s.find('l',3) << endl; //3
//
cout << s.find(s.begin(0,l.end(),'o'));
//倒置串
reverse(s.begin(), s,end());
//string比较
s.compare(); //和strcmp类似
s.substr(1,3) //返回1~3的元素
//插入
s.insert(3,"a") //在s[3]前插入a
//删除指定元素
s.erase()
find()
auto
Day6
set
STL的set用二叉搜索树实现
- set中的元素都是排好序的
- set集合中没有重复的元素
#include<set>
set<int>a;
a.insert(item); //把item放入set
a.begin() //返回set容器第一个元素的迭代器
a.end() //返回一个指向当前set末尾元素的下一位置的迭代器.
a.clear() //删除set容器中的所有的元素
a.empty() //判断set容器是否为空
a.max_size() //返回set容器可能包含的元素最大个数
a.size() //返回当前set容器中的元素个数
a.rbegin() //返回的值和end()相同
a.rend() //返回的值和begin()相同
map
next_permutation()
swap()
list
相较于vector的连续线性空间,list就显得负责许多,它的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元素的移除,list永远是常数时间。

List容器是一个双向链表
- 采用动态存储分配,不会造成内存浪费和溢出
- 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
- 链表灵活,但是空间和时间额外耗费较大
List容器不能像vector一样以普通指针作为迭代器,因为其节点不能保证在同一块连续的内存空间上。List迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取操作。所谓”list正确的递增,递减、取值、成员取用”是指,递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取的是节点的成员。
//list数据元素插入和删除操作
push_back(elem);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与elem值匹配的元素。
//list赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
list& operator=(const list &lst);//重载等号操作符
swap(lst);//将lst与本身的元素互换。
//list数据的存取
front();//返回第一个元素。
back();//返回最后一个元素。

浙公网安备 33010602011771号