刷题笔记 - (updating)
珍爱生命,远离ACM
自测数据三要素
做完题目自己优先测试数据 减少提交次数
- 边界数据(极大/极小)
- 重复数据
- 容易漏掉得数据
1.数组范围
一般我们记住在开数组时一定要比规定的范围多5-10个空间.否则你就会幸运踩坑
例如:限定有10^4个数据
那么 开设数组最好为 type [10005] 有效防止溢出或者边界问题
2.字符串空行问题
当要求我们输入两个字符串时,有时老奸巨猾的出题人会由于某种特殊情况将第一行设置为空行,这是你再想利用cin/scanf给两个字符串赋值时就会出现问题,因为他没有空行过滤所以会一直卡再输入那里,遇到这种情况请使用getline(cin,str)!!!.
三目运算符
如果只涉及到一重if ... else ...
尽可能的用三目运算符表示
C++中将string快速转为int
stoi(string) atoi(const char*)
atoi()的参数是char类型的数组,因此对于一个字符串我们需要先将其利用c_str将该方法转为char *类型的,而stoi()参数是从 const string * 类型不需要转换
例如:
cout<< atoi(string::c_str()) <<endl;
cout<< stoi(string) <<endl;
stoi()会做边界检查,默认实在int 范围内,如果超出会runtime error
atoi()如果超出范围只会输出上界和下界
巨坑之精度转换问题
void func()
{
这里是一个巨坑 还得我两个测试点没过
二刷才发现 关于精度转换问题
不强制转换情况下从int 转换double或者float类型的数据是最好乘上一个 * 1.0!!!
double ans1 = (pronone*100.0) / n ;
double ans2 = (none * 100.0) / n ;
printf("%.1f", ans1); cout << "% ";
printf("%.1f", ans2); cout << "%";
}
map 映射 容器
c++ 中可以使用map映射一个容器类型
map<string,vector<node> > v;
存储 : v[string].push_back(结构体类型);
for (int i = 1; i < n; i++) {
if (data[i].name == data[i - 1].name && data[i - 1].status == 1 && data[i].status == 0) {
custom[data[i - 1].name].push_back(data[i - 1]);
custom[data[i].name].push_back(data[i]);
}
}
判断闰年模板
bool check(int year)
{
if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))return 1;
else return 0;
}
(数学问题)
实际上考察的数学问题,要注意分析十属题目先观察数据是否含有某种规律,在排版数据的时候注意多种方式不要拘泥于一种,更容易发现规律
线性筛素数模板
PAT题目中对于素数的筛选十分常见 需要熟记模板
bool vis[1000000];
int n,cnt = 0,prime[100000];
void shai() {
vis[1] = 1; //注意这里是 i 小于 n
for(int i = 2;i <= n; i++){
if(!vis[i])prime[++cnt] = i;
for(int j = 1; j <=cnt && i * prime[j] <= n; j++ ){
vis[i * prime[j]] = 1; //如果标记位1说明不是素数
if(i % prime[j] == 0)break;
}
}
}
bool isprime(int n)
{
int t = sqrt(n);
for(int i = 2; i <= t;i++)
if(t % i == 0)return false;
return true;
}
注意对某些题目输出 0 数据的检测
例如PAT 1010一元多项式求导问题
if(flag == 0)cout << "0 0"<< endl;
对于条件较多的模拟题一定要先罗列出条件再设计代码
在对变量的命名的时候一定要避开关键字
如: hash map next rank 等
将string类性能转换为 char类型的数组的方法:string.c_str()
常用的几个处理字符串时的内置函数
isalnum() : 判断一个字符是否为字符或者数字
isalpha() : 判断一个字符是否为字母
isupper() : 判断一个字母是否为大写
islower() : 判断一个字母是否为小写
tolower() : 返回一个字母的小写形式
toupper() : 返回一个字母的大写形式
isdigit() : 判断一个字符是否为数字
string.substr(起始位置,截取字串的长度);
string.find(字符串) 成功返回位置索引 失败返回string::npos
string.append(追加长度,追加字符必须是char类型)
a.compare(字符串b) : 比较两个字符串的大小 a > b 返回 1 ,a < b 返回 -1 相等返回 0
如果遇到大量的输入输出不需要思考直接使用scanf 和 printf 大概会缩短一倍的时间
注意看题目给定的数据范围
段错误一般属于数组越界,内存泄漏,或者溢出问题,优先考虑某处的范围限定是否合理观察是运行时存在内存泄漏
变量隔离: 要观察无关的变量的生命周期,判断其是是否会影响之后的代码块
gcd求最大公约数模板
int gcd(int a,int b){
return b == 0 ? a : gcd(b , a % b);
}
在处理字符串输入的时候要考虑是否应该用getline(cin,s);
如果需要用getline 进行输入要确保之前没有输入操作 或者 有一个getchar() 来吸收上一次产生的回车 否则会影响后序的操作
cin会过滤空格字符,想要处理带有空格的字符还是要用getchar()
关于sscanf() 和 ssprintf() 的小技巧
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
using namespace std;
int main()
{
char str[256] = { 0 };
int data = 1024;
//将data转换为字符串
sprintf(str,"%d",data);
puts(str);
//获取data的十六进制
sprintf(str,"0x%X",data);
puts(str);
//获取data的八进制
sprintf(str,"0%o",data);
puts(str);
const char *s1 = "Hello";
const char *s2 = "World";
//连接字符串s1和s2
sprintf(str,"%s %s",s1,s2);
puts(str);
int year,day,a;
char month[10],weekday[10],total[100];
strcpy(total,"sunday June 15 2018");
a = sscanf(total,"%s %s %d %d",weekday,month,&day,&year);
//将total里面的数据从左取出来之后,并存储到相应类型的变量中
//变量使用的是地址,weekday和month使用的是字符数组首地址,
//day和year由于是int类型,所以需要加上取地址符
printf("%d\n",a);//输出返回值
printf("%s %s %d %d\n",weekday,month,day,year);
system("pause");
return 0;
}
如何判断一个数是否为回文数
快速判断
bool check(int x)
{
int m = 0, t = x;
while(t > 0)
{
m = m * 10 + t % 10;
t /= 10;
}
return m == x;
}
判断闰年模板
bool check(int year)
{
if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))return 1;
else return 0;
}
自己的to_string()函数
需要加上头文件 #include
string tostring(int i)
{
stringstream s;
s << i;
string ans = s.str();
return ans;
}