【程序设计竞赛】竞赛中的细节优化

必须强调下,以下的任意一种优化,都应该是在本身采用的算法没有任何问题情况下的“锦上添花”,而不是“雪中送炭”。
如果下面的说法存在误导,请专业大佬评论指正

读写优化

C++读写优化——解除流绑定

在ACM里,经常出现数据集超大造成 cin TLE的情况,其实cin效率之所以低,不是比C低级,而是因为需要与scanf的缓冲区同步,导致效率降低,而且是C++为了兼容C而采取的保守措施。
C++代码中添加 ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);这一段之后,读取速度即可无限趋近于scanfprintf
如果代码首部没有using namespace std; 则要换成std::ios::sync_with_stdio(0),std::cin.tie(0),std::cout.tie(0);

#include <bits/stdc++.h>
using namespace std;int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);// 未使用using namespace std;时使用下方写法// std::ios::sync_with_stdio(0),std::cin.tie(0),std::cout.tie(0);// 代码主体读取、操作、打印
}

std::ios::sync_with_stdio(0)

在 C++ 中,取消同步流(std::ios::sync_with_stdio)是一个常用的技巧,用来加快输入/输出流(I/O)的速度。默认情况下,C++ 的标准库(iostream)与 C 的标准库(stdio)之间是同步的,这意味着它们共享缓冲区,并且每次使用其中一个库的 I/O 功能时,都会刷新另一个库的缓冲区。这保证了数据的一致性,但也增加了性能开销。

通过调用 std::ios::sync_with_stdio(0),你可以取消这种同步,这通常会导致 I/O 操作的速度显著提高。但是,一旦取消了同步,就不能再混用 C++ 和 C 的 I/O 函数(如 cin/cout 和 scanf/printf),因为这可能会导致输出顺序不确定或其他问题。

如果已经采用了C++的输入函数cin,就避免再使用C的scanf;同样的如果已经使用 cout 就避免再使用 printf

cin.tie(0)

在默认的情况下cin绑定的是cout,每次执行的时候都要调用flush,这样会增加IO负担。
这行代码解除了 cin(输入流)与 cout(输出流)之间的绑定。默认情况下,cin 与 cout 绑定在一起,这意味着在每次从 cin 读取之前,cout 的缓冲区都会被自动刷新。通过解除绑定,可以进一步提高 I/O 性能,但这也意味着在输出和输入操作之间不再自动刷新 cout 的缓冲区。

cout.tie(0)

这行代码通常不是必须的,因为 cout 默认情况下并不绑定到其他流。它的主要作用是确保 cout 不与任何其他流(例如 cin 或 cerr)绑定。但在大多数情况下,这行代码并不会改变默认行为。

C++换行输出

endl会输出’\n’(\n是转义字符,代表换行),然后立即刷新缓冲区并输出到屏幕上。由于要刷新缓冲区,endl会比\n慢一点,一般不建议使用。以下是endl实现:

template <class _CharT, class _Traits>
inline _LIBCPP_INLINE_VISIBILITY
basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{__os.put(__os.widen('\n'));__os.flush();return __os;
}

C++中换行大多喜欢写 cout << endl;,然而据acmer和本人赛场亲身经历,这种写法比 cout << '\n; 输出速度要慢许多。当然这不乏出题人的原因,不过为了避免悲剧的发生希望大家还是使用如下两种方法。

  1. 在代码头部使用宏定义#define endl '\n' 替换endl
  2. 改掉使用endl的习惯
#include <bits/stdc++.h>
#define endl '\n'int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);// 上方使用了宏定义,代码编译预处理阶段就将endl换成了'\n'cout << endl;// 直接输出'\n'cout << '\n';
}

C/C++自定义快读快写

本人没有亲自使用过,不过是看别人代码中有如此运用。据说C++17后getchar()/putchar()已经被负优化了,未知真假,个人选择使用。

inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
}inline void write(int x)
{char F[200];int tmp=x>0?x:-x;if(x<0)putchar('-');int cnt=0;while(tmp>0){F[cnt++]=tmp%10+'0';tmp/=10;}while(cnt>0)putchar(F[--cnt]);
}

Java快读快写

大部分初学Java的人应该是使用如下代码进行Java的读写,不过下面这个代码的读写,在面对大量数据的情况下是比较慢的。

import java.util.Scanner;public class Main {public static void main(String[] args) {// java.util 包下的读取Scanner sc = new Scanner(System.in);int n = sc.nextInt();// JavaSystem.out.println(n);sc.close();}
}

下方的读写代码速度较快,经过实践检验,建议采用。该部分代码经过真实调试,应该是不存在什么问题。
特别提醒!!!如果使用了下方代码中的快速输出,代码最后必须使用out.flush(); 必须使用out.flush(); 必须使用out.flush();

快速读入的代码按需使用,写代码时不一定要全部写,如果在XCPC赛场上使用Java,可以提前写好该模板。

import java.io.*;/*** 自定义快读类*/
class Scanner {static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));// 字符串快速读入对象static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));public int nextInt() {try {st.nextToken();return (int) st.nval;} catch (IOException e) {throw new RuntimeException(e);}}public double nextDouble() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return st.nval;}public float nextFloat() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return (float) st.nval;}public long nextLong() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return (long) st.nval;}public String next() {try {st.nextToken();} catch (IOException e) {throw new RuntimeException(e);}return st.sval;}// 按行读入字符串public String readLine() {String s = null;try {s = br.readLine();} catch (IOException e) {e.printStackTrace();}return s;}
}
public class Main {// 快速输出对象static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));public static void main(String[] args) {// 创建自定义的Scanner类Scanner sc = new Scanner();/*** 快读使用案例*/int n = sc.nextInt();double d = sc.nextDouble();float f = sc.nextFloat();// 读入字符串(以空格、回车结尾)String str = sc.next();// 整行读入字符串(以回车换行结尾)String line = sc.readLine();/*** 快速输出使用案例*/out.println(n);out.println(d);out.println(f);out.println(str);out.println(line);// 快速输出必须要刷新缓冲区,否则无法输出out.flush();}
}

读写样例
在这里插入图片描述

其他玄学优化——自行试用

下方玄学,只是部分传言,有些优化的效果似乎并不显著;有时不妨一试。

常用函数优化

inline int abs(int x)
{int y=x>>31;return (x+y)^y;
}
inline int max(int x,int y)
{int m=(x-y)>>31;return (y&m)|(x&~m);
}
inline int min(int x,int y)
{int m=(x-y)>>31;return (y&m|x&~m)^(x^y);
}
inline void swap(int &x,int &y)
{x^=y,y^=x,x^=y;
}
inline int ave(int x,int y)
{return (x&y)+((x^y)>>1);
}

变量自增

++i快于i++

取模非常慢,尽量用减法代替

把函数中的循环变量在整个函数开头用register统一定义好

频繁使用的数用register,和inline一个用法,只不过有可能把变量存入CPU寄存器,来减少时间;某些生命周期不重叠的变量合并,减少创建变量空间的时间。

int main()
{register int i;for (i = 1; i <= n; ++i){// 逻辑部分}for (i = 1; i <= n; ++i){// 逻辑部分}/*下方循环多次使用i*/
}

减少使用STL,他们的常数特别大

现在大部分OJ平台都会自动开O2优化,所以可能STL常数问题可能也没那么严重,有时候也可以尝试手动开O2优化。据说有些时候可能会出现stl的map反而比自己手写map还快的情况…所以自己看情况吧

// 代码头部预处理指令手动打开O2
#pragma GCC optimize(2)

define比赋值更快

定义数组大小时尽量用奇数

尽量不要用bool,int是最快的

if()else() 语句比三元运算符慢;但if语句比三元运算符快

学会合理使用位运算

比如用它判奇偶性。n&1相当于n%2==1。还有一个操作:

inline void swap(int &x,int &y)
{x^=y^=x^=y;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/466701.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud Gateway 网关路由

一、路由断言 路由断言就是判断路由转发的规则 二、路由过滤器 1. 路由过滤器可以实现对网关请求的处理&#xff0c;可以使用 Gateway 提供的&#xff0c;也可以自定义过滤器 2. 路由过滤器 GatewayFilter&#xff08;默认不生效&#xff0c;只有配置到路由后才会生效&#x…

《CSS 简易速速上手小册》第3章:CSS 响应式设计(2024 最新版)

文章目录 3.1 媒体查询基础&#xff1a;网页的智能眼镜3.1.1 基础知识3.1.2 重点案例&#xff1a;适应三种设备的响应式布局3.1.3 拓展案例 1&#xff1a;改变字体大小3.1.4 拓展案例 2&#xff1a;暗模式适配 3.2 响应式图片和视频&#xff1a;让内容自由呼吸3.2.1 基础知识3.…

线性代数的本质——1 向量

向量是线性代数中最为基础的概念。 何为向量&#xff1f; 从物理上看&#xff0c; 向量就是既有大小又有方向的量&#xff0c;只要这两者一定&#xff0c;就可以在空间中随便移动。 从计算机应用的角度看&#xff0c;向量和列表很接近&#xff0c;可以用来描述某对象的几个不同…

力扣刷题之旅:高阶篇(五)—— 网络流算法:最大流与最小割

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 --点击进入刷题地址 引言 在算法领域中&#xff0c;网络流算法是一个重要且实用的工…

Python使用kruskal算法实现最小生成树

假如有多台计算机组成的局域网,不同计算机之间是使用光纤来连接的,如果把计算机看成是一个简单的节点,连接计算机的光纤看成是一条边,那这个局域网就可以抽象成为一个无向图: 添加图片注释,不超过 140 字(可选) 而对于这个图中的每个圆圈代表的是一个计算机,直线代表…

【北邮鲁鹏老师计算机视觉课程笔记】06 corner 局部特征

【北邮鲁鹏老师计算机视觉课程笔记】06 corner 局部特征 1 局部特征的任务牵引&#xff1a;全景拼接 ①提取特征 ②匹配特征 ③拼接图像 我们希望特征有什么特性&#xff1f; ①可重复性 ②显著性 ③计算效率和表达紧凑性 ④局部性 2 特征点检测的任务 3 角点 在角点&#…

Python爬虫之Ajax数据爬取基本原理

前言 有时候我们在用 requests 抓取页面的时候&#xff0c;得到的结果可能和在浏览器中看到的不一样&#xff1a;在浏览器中可以看到正常显示的页面数据&#xff0c;但是使用 requests 得到的结果并没有。这是因为 requests 获取的都是原始的 HTML 文档&#xff0c;而浏览器中…

Kafka 之生产者(Producer)

目录 一. 前言 二. 生产消息 三. 幂等和事务 四. send() 发送消息 五. 原理解析 一. 前言 Kafka生产者是一个应用程序&#xff0c;它负责向 Kafka 主题发送消息。这些消息可以用于多种目的&#xff0c;如记录用户活动、收集物联网设备数据、保存日志消息或缓存即将写入数据…

去空行小工具Html + Javascript

这是一个平常用到的小工具&#xff0c;为了节省屏幕空间把空行去掉&#xff0c;为了怕要用的时候找不到故记录在此。 效果图 网页版&#xff0c;放在浏览器里就可以用 <!doctype html> <html><head><meta charset"utf-8"><title>去…

java微服务面试篇

目录 目录 SpringCloud Spring Cloud 的5大组件 服务注册 Eureka Nacos Eureka和Nacos的对比 负载均衡 负载均衡流程 Ribbon负载均衡策略 自定义负载均衡策略 熔断、降级 服务雪崩 服务降级 服务熔断 服务监控 为什么需要监控 服务监控的组件 skywalking 业务…

Linux基础I/O(三)——缓冲区和文件系统

文章目录 什么是C语言的缓冲区理解文件系统理解软硬链接 什么是C语言的缓冲区 C语言的缓冲区其实就是一部分内存 那么它的作用是什么&#xff1f; 下面有一个例子&#xff1a; 你在陕西&#xff0c;你远在山东的同学要过生日了&#xff0c;你打算送给他一份生日礼物。你有两种方…

C++ //练习 5.24 修改你的程序,使得当第二个数是0时抛出异常。先不要设定catch子句,运行程序并真的为除数输入0,看看会发生什么?

C Primer&#xff08;第5版&#xff09; 练习 5.24 练习 5.24 修改你的程序&#xff0c;使得当第二个数是0时抛出异常。先不要设定catch子句&#xff0c;运行程序并真的为除数输入0&#xff0c;看看会发生什么&#xff1f; 环境&#xff1a;Linux Ubuntu&#xff08;云服务器…