C ++ 语法细节

105 阅读4分钟

vector 容器越界:

在我们使用vector等容器的时候 , 往往会出现一些越界访问,只是我们没有意识到。

比如:直接使用下标访问 , 但是size没有变化。 这是因为 , 容器往往会先预先多开辟一些空间 , 使用size维护大小 , 但是通过下标访问的话 , 空间可能是存在的 , 但是容器逻辑空间没有开辟。

对于这种情况:要么指定size , 要么 push_back(element) 直接压入元素 但是通过下标(其大于等于size)直接访问 , 可能导致越界也不会更新 size.

// 这种方式是合法的
std::cin >> n;
std::vector<int> v(n);

for (int i = 0; i < n; i ++ )
    std::cin >> v[i];
                
std::cout << v.size() << '\n';

技巧 (计算机程序运行时间)

此代码显示的结果是秒s(保留后面6位小数)

#include <iostream>
#include <time.h>

int main(){

	clock_t start , end;

	start = clock(); 
   /*
    需要测试时间的代码
   */
        
	end = clock();

	std::cout << double(end - start) / CLOCKS_PER_SEC;

	return 0 ;
}

关于关闭同步流

一般大家为了加速读入,都会关闭同步流。

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

关闭同步流就不能使用scanf , 不然会导致运行错误。 但是 std::coutprintf 是被允许混用的 , 但是会出现这样的问题。

image.png

image.png

printf 会先输出 ,无论先后。

printf 输出的精度问题

printf("%_lf") 其中__ 是你需要指定的精度 , 你可以指定11位 , 8 位等等。

C ++ 也有精度输出管理的函数。 #include 引入一下这个头文件

double a = 0.1230;
std::cout<< std::fixed << std::setprecision(5) << a ;//输出 0.12300

这样指定类似于 printf("%5lf" , a); , 但是请注意这样的指定对后面的浮点数数据输出都有效!

关于long long 的使用

image.png 这样是会爆int ,后面的运算的类型依旧是 int。 所以需要将这种复合运算,请在后面指定一下类型。

比如这样:

image.png 这样后面的类型就自动long long , 而不会爆 int。

对于比赛中遇到的精度问题

比赛中可能会出现一些精度问题,比如std::log2()std::log2()函数 , 对于这一类数可能存在是无理数,会有一定的精度误差,这是正常情况,只要差距非常小,那么就不用担心。

举例:

image.png

我的程序对于上面那个H(s) 的计算的结果: image.png

题中给出的答案:1.3083

code

    std::string s;
    std::cin >> s;

    double t0 = std::count(s.begin() , s.end() , '0');
    double t1 = std::count(s.begin() , s.end() , '1');

    double t = t0 + t1;

    std::cout << -1 * (t0 * (t0) / t * (std::log2(t0) - std::log2(t)) + 
    t1 * (t1) / t * (std::log2(t1) - std::log2(t))) << '\n';

所以题中给出的答案和实际计算的答案是有一定的误差的

对于浮点数我们就不能使用这种 == , 这种逻辑运算符。 笔者是如何解决的呢?

给定误差区间即可

image.png

如果给定的误差区间非常小 , 没有输出一个答案的话 ,就稍微扩大一点点区间。看看能不能输出答案,切记不要有满足区间的就跳出,因为可能你区间开大了,可能存在有更符合条件的,你再适当缩小区间寻找答案即可。

关于double 存在精度丢失

double 一般情况下算出来的都是比较准的,但是存在一些时候有精度丢失。 比如这题 引入double 就wa, 必须直接算出来,然后直接向下取整,这样就不会存在答案少1 , 甚至少2 ,类似于这种因为非常小的精度丢失乘上一个非常大整数导致答案不准确。

举例:

#include <iostream>
#include <iomanip>

int main() {

   // double 想最近的整数向下取整
   // (a * b) / (c * d) 
   // (a * b) % (c * d)
   float a = 10.0;
   float b = 0.1;
   float c = a - b;

   std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(23)
       << "c = " << c << "\n";

   return 0;
}

答案:

image.png 这意味因为对于一些无限循环小数计算机不能完全存储下来 , 那么只能截断存储,然后四舍五入了。 所以如果题目要求结果保留2位小数,可是使用double运算。 但是题目要求输出向下取整的结果,那么请尽量使用整数运算,不然会wa 的很惨。

image.png