当前位置:首页 » 《随便一记》 » 正文

0x01基础中的进阶——深度解析各种算法竞赛中常用的编程小技巧(1.0持续更新)_u012681544的博客

3 人参与  2021年11月14日 09:23  分类 : 《随便一记》  评论

点击全文阅读


先上一段代码

Warning:部分功能DevC++不支持,请使用对GNU c++17有较好支持的编译器

#include "bits/stdc++.h"
//#pragma GCC optimize ("O3")
//#pragma GCC target ("sse4")
 
using namespace std;

#define DEBUG

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;
 
typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;
 
typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;
 
template<class T> using pq = priority_queue<T>;
template<class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
 
#define FOR(i, a, b) for (int i=(a); i<=(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define trav(a,x) for (auto& a : x)
#define uid(a, b) uniform_int_distribution<int>(a, b)(rng)
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
//#define f first
//#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()
#define ins insert
#define MAX 1001111
 
template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }
 
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
 
void __print(int x) {cerr << x;}
void __print(long x) {cerr << x;}
void __print(long long x) {cerr << x;}
void __print(unsigned x) {cerr << x;}
void __print(unsigned long x) {cerr << x;}
void __print(unsigned long long x) {cerr << x;}
void __print(float x) {cerr << x;}
void __print(double x) {cerr << x;}
void __print(long double x) {cerr << x;}
void __print(char x) {cerr << '\'' << x << '\'';}
void __print(const char *x) {cerr << '\"' << x << '\"';}
void __print(const string &x) {cerr << '\"' << x << '\"';}
void __print(bool x) {cerr << (x ? "true" : "false");}
 
template<typename T, typename V>
void __print(const pair<T, V> &x) {cerr << '{'; __print(x.first); cerr << ", "; __print(x.second); cerr << '}';}
template<typename T>
void __print(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? ", " : ""), __print(i); cerr << "}";}
void _print() {cerr << "]\n";}
template <typename T, typename... V>
void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifdef DEBUG
#define dbg(x...) cerr << "\033[1m\033[31m"<<__func__<<":"<<__LINE__<<" [" << #x << "] = ["; _print(x); cerr <<"\033[1m\033[31m"<< endl;
#else
#define dbg(x...)
#endif
 
const char nl = '\n';

int n,m,q,a[MAX];
 
int find(int q,int l,int r)
{
    while(l<r)
    {
        int mid=(l+r)>>1;
        //cerr<<l<<" "<<r<<endl;
        if(a[mid]>=q)r=mid;
        else l=mid+1;
    }
    if(a[l]==q)return l+1;
    else return -1;
}

void solve()
{
    cin>>n>>m;
    F0R(i,n)cin>>a[i];
    F0R(i,m)
    {
        cin>>q;
        cout<<find(q,0,n-1)<<" ";
    }
}
 
int main() 
{
    cin.tie(0)->sync_with_stdio(0); //no string
    cin.exceptions(cin.failbit);// RE->WA

    #ifdef DEBUG
	freopen("a.in","r",stdin); 
	freopen("a.out","w",stdout); 
    #endif
    
    solve();

	//getchar();
    //system("PAUSE");
	return 0;
}

懂行的人会说这不就是一个简单的二分嘛,整这么麻烦干啥
新手可能会被吓一大跳

在cf和luogu月赛等线上算法竞赛,和一些线下算法竞赛中,快速的进行编程和调试是我们所需要做到的,而一个优秀的程序框架则可以大大的简化我们的编程与调试过程(ps:线下不用全部输入,只要写需要的部分!!!)

不用担心! 我接下来会向大家逐段解答



0x00头文件

说到头文件便不得不提到#include "bits/stdc++.h"

<>和""效果相同
业内称之为万能头文件,如果没有这个你可能有时要在文件开头输入数十个头文件
#include <algorithm>     //通用算法
#include <bitset>      //位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>     //复数类
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>      //双端队列容器
#include <exception>    //异常处理类
#include <fstream>
#include <functional>    //定义运算函数(代替运算符)
#include <limits>
#include <list>       //线性列表容器
#include <map>       //映射容器
#include <iomanip>
#include <ios>      //基本输入/输出支持
#include <iosfwd>    //输入/输出系统使用的前置声明
#include <iostream>
#include <istream>     //基本输入流
#include <ostream>     //基本输出流
#include <queue>       //队列容器
#include <set>       //集合容器
#include <sstream>     //基于字符串的流
#include <stack>     //堆栈容器    
#include <stdexcept>    //标准异常类
#include <streambuf>   //底层输入/输出支持
#include <string>     //字符串类
#include <utility>     //通用模板类
#include <vector>     //动态数组容器
#include <cwchar>
#include <cwctype>
#include <complex.h>  //复数处理
#include <fenv.h>    //浮点环境
#include <inttypes.h>  //整数格式转换
#include <stdbool.h>   //布尔环境
#include <stdint.h>   //整型环境
#include <tgmath.h>  //通用类型数学宏

看吧,多么令人崩溃,有时忘记了某个还会一直报错

但是万能头文件虽好,但是一定要注意自己所参加的竞赛是否支持,其他的头文件也是一定要牢记的,认识头文件也是更好的学习c++函数的基础



0x01手动优化

#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")
手动开启O3优化,并加速sse4指令集

下面附赠一个网传40行玄学优化,有时毫无用处。但有时却有大幅优化,具体原理大家自行百度

#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")



0x02命名空间

利用using namespace std来避免在引用c++std类函数时多次使用std::



0x03简化变量和函数声明

利用typedef#define来将复杂的变量和函数声明简化

例如:
1.本来声明无符号的长整型需要用unsigned long long a;
但是在声明过typedef unsigned long double uld;
后便可以只通过ull a;来声明变量
2.进行从a到b的循环需要输入for (int i=a; i<=b; i++)
而声明过#define FOR(i, a, b) for (int i=(a); i<=(b); i++)
则可以简单地通过FOR(i, a, b)来代替
(ps:括号不可缺少,否则可能会出现运算错误)



0x04提前预置比较函数cmp

方便通过sort直接比较各种不是简单整型而是结构体中的整型或对象和类中的整型

template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }



0x05提前预置随机数函数

利用mt19937配置‘真’随机数(bushi

茅台19937[doge]
ps:直接用random函数cf中不支持哦,会WA的



0x06提前预置调试函数

在文件输入输出时直接利用cerr在窗口中快速输出所需监视的变量,方便查错



0x07提前预置打表函数

在算法竞赛中,不免遇到数据有限的问题,或者是你的算法耗时过长的问题,这时候利用提前预置的打表函数,可以快速的制作答案数组(我更喜欢用python打表lalala~~



0x08提前预置调试函数

利用dbg()可以快速在程序无法停机时或者出错时对于某个变量进行分析

其中\033[1m\033[31m是控制字体颜色的,linux编译器才会提供支持,win上也可以实现不过略麻烦,在此不做说明,请自行百度



0x09简化换行符

const char nl = '\n';



0x0a加速输入输出

cin.tie(0)->sync_with_stdio(0);

有时的题目会刻意卡cin、cout的速度(多无聊啊)

或者是你自己懒得打scanf和printf但又想要程序快一点点,可以利用这句代码断开默认的tie,加速cin

ps:输入字符类的时候不能声明这句话!!!!!

有的时候需要更快的时候要快读哦

inline int read()
{
    int x=0; bool f=1; char c=getchar();
    //while(!isdigit(c)){if(c=='-') f=0; c=getchar();}
    while(isdigit(c)){x=x*10+c-'0'; c=getchar();}
    //if(!f) return 0-x;
    return x;
}
非递归函数加inline在函数声明之前会快一点哦(将函数由编译器放在main中,不过有的编译器不认的)



0x0bRE->WA

乍一看是不是很傻,不过有的时候由于数组越界和变量越界而出现的问题太难查出了,有了这句话可以有亿些帮助
cin.exceptions(cin.failbit);// RE->WA



0x0c文件输入输出

线下比赛都需要文件输入输出,而利用vscode、sublime等进行调试的时候文件输入输出我个人认为十分方便(dev窗口就ok了),尤其是输入数据量比较庞大的时候。

利用ifdef结构可以仅仅通过注释掉#define DEBUG便能同时注释掉调试函数和文件输入输出,避免在线上刷题时因为忘记注释掉文件输入输出而RE的尴尬
(我之前老是因为这个RE wuwuwu



0x0e利用getchar和system指令避免窗口闪退



0x0d结语

这一讲就到此结束,如果博主发现了什么新的技巧会及时进行补充,也欢迎各位大佬进行指正或提出自己的编程小tips


点击全文阅读


本文链接:http://zhangshiyu.com/post/30846.html

函数  预置  容器  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1