NOIP比赛中如何加速c++的输入输出
NOIP比赛中如何加速c++的输入输出
在竞赛中,遇到大数据时,往往需要更快的读取方式。由于比赛中输出一般规模较小,本文只讨论输入如何加速.
现在我们生成1000000个随机数,构成1000*1000的矩阵,然后输入比较时间(Win 10系统)
#include<iostream> #include<stdlib.h> #include<ctime> using namespace std; int main(){ srand((unsigned)time(NULL)); freopen("out1.txt","w",stdout); for(int i=1;i<=1000;i++){ for(int j=1;j<=1000;j++){ cout<<rand()<<' '; } cout<<endl; } }
cin的速度
在比赛中,经常出现数据集超大造成 cin TLE的情况。这时候大部分人(包括原来我也是)认为这是cin的效率不及scanf的错
准确的说,cin在不优化的情况下效率是很低的,我们来测试一下
#include<iostream> #include<cstdio> #include<ctime> using namespace std; int a[1005][1005]; int main(){ freopen("out1.txt","r",stdin); double s=clock(); for(int i=1;i<=1000;i++){ for(int j=1;j<=1000;j++){ cin>>a[i][j]; } } printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC); }
可以看出,cin的用时达到了惊人的0.763s!!!假如运行时间限制为1s,那么程序只剩下0.3秒来计算,是极容易TLE的
因此,遇到大数据时尽量避免用cin
有博客提到:
默认的时候,cin与stdin总是保持同步的,也就是说这两种方法可以混用,而不必担心文件指针混乱,同时cout和stdout也一样,两者混用不会输出顺序错乱。正因为这个兼容性的特性,导致cin有许多额外的开销,如何禁用这个特性呢?只需一个语句std::ios::sync_with_stdio(false);,这样就可以取消cin与stdin的同步了
其实还有一个等价的写法
cin.tie(0);//取消cin的同步 cout.tie(0);//取消cout的同步
我们来验证一下:
#include<iostream> #include<cstdio> #include<ctime> using namespace std; int a[1005][1005]; int main(){ freopen("out1.txt","r",stdin); std::ios::sync_with_stdio(false);//优化 double s=clock(); for(int i=1;i<=1000;i++){ for(int j=1;j<=1000;j++){ cin>>a[i][j]; } } printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC); }
时间变成了0.173s,相比cin是飞跃性的优化
但是别急着高兴,本人亲测,在NOIP的评测机上这样子会爆0
因此,noip比赛中坚决不要写std::ios::sync_with_stdio(false)
爆0的原因如下
noip明确要求使用freopen,而freopen是stdio库中的,既然我们已经取消了iostream和stdio的同步,这样会造成文件指针混乱,进而导致RE
scanf的速度
既然noip比赛中坚决不要写std::ios::sync_with_stdio(false),那么我们可以用scanf
#include<iostream> #include<cstdio> #include<ctime> using namespace std; int a[1005][1005]; int main(){ freopen("out1.txt","r",stdin); double s=clock(); for(int i=1;i<=1000;i++){ for(int j=1;j<=1000;j++){ scanf("%d",&a[i][j]); } } printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC); }
时间变成了0.641s,相比无优化的cin还是较快的
手写快速读入的速度
我们知道,getchar的速度是很快的,但它只能读取单个字符,因此,我们通过将字符转为整型来优化,同理可以转成long long
快速读入的代码NOIP初赛曾经考过
#include<iostream> #include<cstdio> #include<ctime> using namespace std; int a[1005][1005]; inline int read(){//非常重要的快速读入代码 int x=0,sign=1; char c=getchar(); while(c>'9'||c<'0'){//判断符号 if(c=='-') sign=-1; c=getchar(); } while(c>='0'&&c<='9'){//转换数 x=x*10+c-'0'; c=getchar(); } return x*sign; } int main(){ freopen("out1.txt","r",stdin); double s=clock(); for(int i=1;i<=1000;i++){ for(int j=1;j<=1000;j++){ a[i][j]=read(); } } printf("time used=%.3fs\n",double(clock()-s)/CLOCKS_PER_SEC); }
运行后的结果如下:
现在这个方法只需0.163s,比其他的方法都快,而且不会在评测机上出现问题,并且也没有调用许多函数
遇到数据量大的题,尽量用手写的快速读入来读取
总结
- 遇到大数据时尽量避免用cin
- noip比赛中写std::ios::sync_with_stdio(false)时,不能把scanf,printf和cin,cout混用
- 如果是double或输入格式较复杂用scanf
- 遇到数据量大的题,且是long long或int,尽量用手写的快速读入来读取
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· C#高性能开发之类型系统:从 C# 7.0 到 C# 14 的类型系统演进全景
· 从零实现富文本编辑器#3-基于Delta的线性数据结构模型
· 记一次 .NET某旅行社酒店管理系统 卡死分析
· 长文讲解 MCP 和案例实战
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· C#高性能开发之类型系统:从 C# 7.0 到 C# 14 的类型系统演进全景
· 管理100个小程序-很难吗
· 基于Blazor实现的运输信息管理系统
· 如何统计不同电话号码的个数?—位图法
· 聊聊四种实时通信技术:长轮询、短轮询、WebSocket 和 SSE