当前位置: 首页 > news >正文

快读快写 学习笔记

在OI中,经常有输入输出量巨大的题,这一类题一般需要非常快速的输入输出方式,于是便有了快读快写

下面是模板(原理无需理解,用的时候直接复制上就行):

#include <cstdio>
#include <cctype>
using namespace std;
int precision=-1;
char buf[100000],*p1=buf,*p2=buf;
#define nextChar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
inline int scan_int(){int x=0,f=1;char ch=nextChar();while(ch<48||ch>57){if(ch=='-')f=-1;ch=nextChar();}while(ch>=48&&ch<=57){x=(x<<3)+(x<<1)+(ch^48);ch=nextChar();}return x*f;
}
inline double power(double a,int k){double res=1;while(k){if(k&1) res*=a;a=a*a;k>>=1;}return res;
}
inline double scan_double(){double x=0,y=0;int f=1,mine=0;char ch=nextChar();while(ch<48||ch>57){if(ch=='-')f=-1;ch=nextChar();}while(ch>=48&&ch<=57){x=x*10+(ch^48);ch=nextChar();}if(ch=='.'){ch=nextChar();while(ch>=48&&ch<=57){y=y*10+(ch^48);mine++;ch=nextChar();}}precision=mine;return f*(x+y/power(10,mine));
}
inline bool scan_bool(){int x=scan_int();return x!=0;
}
inline char scan_char(){char ch=nextChar();while(isspace(ch)) ch=nextChar();return ch;
}
const int BUF_SIZE=1<<20;
char output_buffer[BUF_SIZE],*output_ptr=output_buffer;
inline void flush_output(){fwrite(output_buffer,1,output_ptr-output_buffer,stdout);output_ptr=output_buffer;
}
inline void print_int(int x){if(x<0){*output_ptr++='-';x=-x;}char temp[20];int len=0;do{temp[len++]='0'+(x%10);x/=10;}while(x);while(len--) *output_ptr++=temp[len];if(output_ptr-output_buffer>=BUF_SIZE-20) flush_output();
}
inline void print_double(double x){char temp[30];int len;if(precision<0) len=snprintf(temp,sizeof(temp),"%.f",x);else len=snprintf(temp,sizeof(temp),"%.*f",precision,x);for(int i=0;i<len;i++) *output_ptr++=temp[i];if(output_ptr-output_buffer>=BUF_SIZE-20) flush_output();
}
inline void print_bool(bool x){const char *str=x?"true":"false";while(*str) *output_ptr++=*str++;if(output_ptr-output_buffer>=BUF_SIZE-20) flush_output();
}
inline void print_char(char x){*output_ptr++=x;if(output_ptr-output_buffer>=BUF_SIZE-20) flush_output();
}
int main(){int a=scan_int();double b=scan_double();bool c=scan_bool();char d=scan_char();print_int(a);print_char('\n');print_double(b);print_char('\n');print_bool(c);print_char('\n');print_char(d);print_char('\n');flush_output();return 0;
}

例题1:洛谷 - P10815 【模板】快速读入

题目链接

实际难度:\(\color{F39C11}{{普及-}}\)

考察知识点

思路分析

模板题

复杂度分析

时间复杂度

\[\begin{aligned} T(n)&=\underbrace{O(n)}_{输入}+\underbrace{O(1)}_{计算}+\underbrace{O(1)}_{输出} \\ &=O(1) \end{aligned} \]

空间复杂度

  • 主要存储:\(O(1)\)
  • 临时变量:\(O(1)\)
  • 总空间:\(O(1)\)

C++代码

// Problem: P10815 【模板】快速读入
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P10815
// Memory Limit: 2 MB
// Time Limit: 2500 ms
// 
// Powered by CP Editor (https://cpeditor.org)// 包含标准输入输出库,用于fread、fwrite等底层IO函数
#include <cstdio>
// 包含字符分类函数库,用于isspace(判断空白字符)等函数
#include <cctype>
using namespace std;// 全局变量:记录浮点数的小数位数(精度),初始为-1表示未指定精度
int precision = -1;
// 输入缓冲区:大小100000字节,用于批量读取输入数据(减少IO次数,提高速度)
char buf[100000];
// 缓冲区指针:p1指向当前读取位置,p2指向缓冲区末尾(已读取数据的边界)
char *p1 = buf, *p2 = buf;// 宏定义nextChar:从输入缓冲区读取下一个字符,缓冲区空则用fread填充
// 逻辑:若p1==p2(缓冲区已读完),则用fread从stdin读100000字节到buf,更新p1和p2
// 若仍无数据(p1==p2,说明到达EOF),返回EOF;否则返回p1指向的字符并让p1后移
#define nextChar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)// 快速读取整数函数:处理正负整数,比scanf更快(减少格式化解析开销)
inline int scan_int() {int x = 0;    // 存储读取的整数结果,初始为0int f = 1;    // 符号标志:1表示正数,-1表示负数,初始为正char ch = nextChar();  // 读取第一个字符// 跳过非数字字符(直到遇到数字或负号)while (ch < 48 || ch > 57) {  // 48是'0'的ASCII,57是'9'的ASCII,此条件判断非数字if (ch == '-') f = -1;    // 若遇到负号,将符号标志设为-1ch = nextChar();          // 继续读取下一个字符}// 读取数字部分,计算整数结果while (ch >= 48 && ch <= 57) {  // 仅处理数字字符// x = x*10 + (ch-'0'):位运算优化(x<<3是x*8,x<<1是x*2,总和x*10)// ch^48等价于ch-'0'(因'0'ASCII=48,异或后低4位为数字值)x = (x << 3) + (x << 1) + (ch ^ 48);ch = nextChar();  // 继续读取下一个字符}return x * f;  // 返回带符号的整数结果
}// 快速幂函数:计算a的k次幂(用于浮点数小数部分的分母计算,a=10,k=小数位数)
inline double power(double a, int k) {double res = 1;  // 结果初始为1(乘法单位元)while (k) {      // 当指数k不为0时循环if (k & 1)   // 若k为奇数(二进制最低位为1),将当前a乘到结果中res *= a;a = a * a;   // a自乘,指数翻倍(对应二进制右移一位)k >>= 1;     // k右移一位(等价于k=k/2,整数除法)}return res;  // 返回a^k的结果
}// 快速读取浮点数函数:处理整数部分、小数部分,支持正负,记录精度
inline double scan_double() {double x = 0;   // 存储浮点数的整数部分,初始为0double y = 0;   // 存储浮点数的小数部分,初始为0int f = 1;      // 符号标志:1正-1负,初始为正int mine = 0;   // 记录小数位数,初始为0char ch = nextChar();  // 读取第一个字符// 跳过非数字字符(直到遇到数字、负号或小数点)while (ch < 48 || ch > 57) {if (ch == '-') f = -1;  // 遇到负号,设置符号为负ch = nextChar();        // 继续读下一个字符}// 读取整数部分while (ch >= 48 && ch <= 57) {x = x * 10 + (ch ^ 48);  // 整数部分累加(x*10 + 当前数字)ch = nextChar();         // 继续读下一个字符}// 若遇到小数点,处理小数部分if (ch == '.') {ch = nextChar();  // 跳过小数点,读取小数部分第一个字符// 读取小数部分,累加至y(y初始为0,每次乘10加当前数字)while (ch >= 48 && ch <= 57) {y = y * 10 + (ch ^ 48);mine++;       // 小数位数+1ch = nextChar();  // 继续读下一个字符}}precision = mine;  // 记录当前浮点数的小数位数(供后续输出使用)// 计算最终浮点数:符号 * (整数部分 + 小数部分/10^小数位数)return f * (x + y / power(10, mine));
}// 快速读取布尔值函数:读取整数,非0为true,0为false
inline bool scan_bool() {int x = scan_int();  // 调用scan_int读取整数return x != 0;       // 整数非0返回true,否则返回false
}// 快速读取字符函数:跳过空白字符(空格、换行、制表符等),读取第一个有效字符
inline char scan_char() {char ch = nextChar();  // 读取第一个字符// isspace(ch)判断是否为空白字符(空格、\n、\t等),跳过所有空白while (isspace(ch))ch = nextChar();return ch;  // 返回第一个非空白字符
}// 输出缓冲区配置:BUF_SIZE为2^20字节(约1MB),用于批量写入输出数据
const int BUF_SIZE = 1 << 20;
char output_buffer[BUF_SIZE];  // 输出缓冲区数组
char *output_ptr = output_buffer;  // 输出缓冲区指针,指向当前写入位置// 刷新输出缓冲区函数:将缓冲区中已写入的数据写入stdout,重置指针
inline void flush_output() {// fwrite:从output_buffer写数据到stdout,每次写1字节,共写(output_ptr - output_buffer)字节fwrite(output_buffer, 1, output_ptr - output_buffer, stdout);output_ptr = output_buffer;  // 指针重置到缓冲区起始位置,准备下次写入
}// 快速输出整数函数:处理正负整数,写入输出缓冲区(比printf快)
inline void print_int(int x) {// 若x为负数,先写入负号'-',并将x转为正数if (x < 0) {*output_ptr++ = '-';  // 缓冲区指针后移,指向下次写入位置x = -x;}char temp[20];  // 临时数组:存储数字的逆序(因取模得到的是个位、十位...)int len = 0;    // 记录数字的位数,初始为0// 循环取模获取数字的每一位(从个位开始),存入tempdo {temp[len++] = '0' + (x % 10);  // x%10得到个位,转为字符x /= 10;                       // x除以10,去掉个位} while (x);  // 直到x为0(do-while确保x=0时也会存入一个'0')// 倒序输出temp中的字符(从高位到低位),写入缓冲区while (len--)*output_ptr++ = temp[len];// 检查缓冲区是否即将满(预留20字节防止溢出),满则刷新if (output_ptr - output_buffer >= BUF_SIZE - 20)flush_output();
}// 快速输出浮点数函数:按precision记录的精度格式化,写入输出缓冲区
inline void print_double(double x) {char temp[30];  // 临时数组:存储格式化后的浮点数字符串int len;        // 记录格式化后字符串的长度// 按精度格式化浮点数:// precision<0时,用"%.f"(无小数部分,四舍五入到整数)// 否则用"%.*f"(*表示精度由precision指定,保留precision位小数)if (precision < 0)len = snprintf(temp, sizeof(temp), "%.f", x);elselen = snprintf(temp, sizeof(temp), "%.*f", precision, x);// 将格式化后的字符串写入输出缓冲区for (int i = 0; i < len; i++)*output_ptr++ = temp[i];// 检查缓冲区是否即将满,满则刷新if (output_ptr - output_buffer >= BUF_SIZE - 20)flush_output();
}// 快速输出布尔值函数:输出"true"或"false"字符串到缓冲区
inline void print_bool(bool x) {// 若x为true,取"true"字符串;否则取"false"字符串const char *str = x ? "true" : "false";// 遍历字符串,逐个字符写入缓冲区while (*str) {*output_ptr++ = *str++;  // 将当前字符写入输出缓冲区,指针后移}// 检查缓冲区是否即将满(预留20字节防溢出),满则刷新if (output_ptr - output_buffer >= BUF_SIZE - 20)flush_output();
}// 快速输出单个字符函数:将字符写入输出缓冲区,按需刷新
inline void print_char(char x) {*output_ptr++ = x;  // 直接将字符x写入缓冲区,缓冲区指针后移// 检查缓冲区是否即将满(预留20字节防溢出),满则刷新if (output_ptr - output_buffer >= BUF_SIZE - 20)flush_output();
}// 主函数:示例用法——读取n个整数,计算它们的和并输出
int main() {// 1. 读取整数n:表示后续要读取的整数个数int n = scan_int();// 2. 定义sum变量:用于累加n个整数的和,初始化为0int sum = 0;// 3. 循环n次:每次读取一个整数,累加到sum中for (int i = 1; i <= n; i++) {sum += scan_int();  // 调用快速读入函数获取整数,加入总和}// 4. 输出结果:print_int(sum);       // 调用快速输出函数,将累加和写入输出缓冲区print_char('\n');     // 输出换行符,确保结果格式正确(单独占一行)flush_output();       // 强制刷新输出缓冲区:确保所有数据都写入stdout(避免缓冲区残留)return 0;  // 程序正常结束
}
http://www.wxhsa.cn/company.asp?id=3424

相关文章:

  • Ubuntu 安装 CLion
  • AI编程实战
  • 25/9/13(补)
  • 面向对象编程(OOP)的原则
  • 【龙智Atlassian插件】Confluence周报插件上线AI智能总结,一键生成专业报告 - 实践
  • 数字化(管理)系统的工具化思考
  • 详细介绍:传统神经网络实现-----手写数字识别(MNIST)项目
  • C#语言中使用using关键字
  • 中育新版本OSS Token获取API分析
  • 25/9/12(补,上一篇是9/11的)
  • 动态编译 vs. 静态编译,容器时代那个更有优势?
  • 实用指南:操作系统类型全解析:从批处理到嵌入式
  • 【C++ 类和对象・高阶深化(下)】再探构造函数(含初始化列表),吃透 static 成员、友元、内部类及对象拷贝编译器优化 - 指南
  • VSCode 运行 C/C++ 程序
  • 3 字节
  • Springcloud Alibaba(一)
  • 111111111
  • 202204_DASCTF_SimpleFlow
  • 使用 Winscope 跟踪窗口转换
  • 25/9/12(补)
  • 深入解析:“纳米总管”——Arduino Nano 的趣味生活
  • 洛谷题目难度系统优化
  • 202112_摆烂杯_WhatAHack!
  • 少儿 500 常用汉字 字帖
  • Ubuntu 安装 gcc
  • Redis常见性能问题
  • 3 线性模型
  • 详细介绍:七彩喜智慧养老:用科技温暖晚年,让关爱永不掉线
  • P3522 [POI 2011] TEM-Temperature
  • 202105_风二西_SQL基于时间盲注