程序设计竞赛常用结构C++模板

1.前言

在平时刷题中,有一些结构是经常使用的,比如输入函数,输出函数,还有循环结构,以及一些常用的变量和结构。而利用C++中的宏定义#define,类型重命名typedef,宏常量const,以及重载等等这些特性,可以事先写好常用的结构,然后就可以快速地写出符合自己习惯的代码。因为程序设计比赛的时候往往时间是有限的,所以要想方设法地节约写代码的时间,这不失为一种方法。比赛跟工程还是不一样的,比赛是跟时间赛跑,工程要求可读性好。

其实之前在本科的时候,我就有一些符合自己习惯的模板,但忘了发博客了,现在补上,以方便日后自己用,也给大家一个参考。

2.代码

#include<bits/stdc++.h>
#define lson l,m,rt<<1  
#define rson m+1,r,rt<<1 | 1  
#define ffr(i,x,y) for(int i=(x),_en=(y);i<=_en;i++)  
#define rff(i,x,y) for(int i=(x),_en=(y);i>=_en;i--)  
#define clr(f,z) memset(f,z,sizeof(f)) 
using namespace std;
typedef double db;
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef pair<int,int> pa;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxn=1005,inf=1<<29,mod=1000000007;
const double pi=acos(-1.0);
bool sf(int &x){return scanf("%d",&x)==1;}
bool sf(ll &x){return scanf("%I64d",&x)==1;}
bool sf(double &x){return scanf("%lf",&x)==1;}
bool sf(char &x){return scanf("%c",&x)==1;}
bool sf(char *x){return scanf("%s",x)==1;}
bool sf(string &x){return cin>>x;}
template<class T>inline void sf2(T&num){
    num=0;T f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    num*=f;
}
void pf(int x,int op){op==0?printf("%d",x):printf("%d%c",x,op==1?' ':'\n');}
void pf(ll x,int op){op==0?printf("%I64d",x):printf("%I64d%c",x,op==1?' ':'\n');}
void pf(char x,int op){op==0?printf("%c",x):printf("%c%c",x,op==1?' ':'\n');}
void pf(char *x,int op){op==0?printf("%s",x):printf("%s%c",x,op==1?' ':'\n');}
void pf(string x,int op){op==0?cout<<x:cout<<x<<(op==1?' ':'\n');}
inline int gcd(int x,int y){if(!x)return y;return gcd(y%x,x);}
inline int power(int x,int k,int p){int res=1;for(;k;k>>=1,x=(ll)x*x%p)if(k&1)res=(ll)res*x%p;return res;}
int n,m,k;
int dp[maxn][maxn],a[maxn][maxn];
int dir[][2]={{0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};
int main()
{
	
	return 0;
}
3.解释

对于代码段:

#include<bits/stdc++.h>

bits/stdc++.h这个头文件,号称是包含所有C++头文件的头文件,只能说666666,不过有些OJ可能不支持哦,正规比赛最好老老实实地一个个头文件敲吧。

对于代码段:

#define lson l,m,rt<<1  
#define rson m+1,r,rt<<1 | 1 

这两个宏定义是为了计算树里面左右儿子节点。在线段树里用的比较多,比如当前节点维护的是[l,r],令m=(l+r)/2,那么左儿子维护的是[l,m],右儿子维护[m+1,r]。

对于代码段:

#define ffr(i,x,y) for(int i=(x),_en=(y);i<=_en;i++)  
#define rff(i,x,y) for(int i=(x),_en=(y);i>=_en;i--)  
#define clr(f,z) memset(f,z,sizeof(f)) 

有木有觉得写for循环很累,从现在起,比如你要写for(int i=0;i<=10;i++) 只需要写成ffr(i,0,10)就可以了,是不是省了不少力?

rff刚好是个倒序循环。

对于ACM,经常要多组输入,那很多时候,变量啊,数组啊就要清空初始化,那就要用memset,代码贼长,现在,有了这个宏定义,比如要把数组a(不管几维都可以)清空,那就可以clr(a,0)或者clr(a,-1),贼方便,同时要注意,z的值只能是0或者-1哦,这是因为memset这个函数只能把数组每个元素搞成0或者-1,因为0的二进制补码表示是全0,-1的二进制补码表示是全1,重置起来方便嘛。那如果你要重置成某个特定的别的值,就要么就自己循环重置,要么就用C++里的fill函数。

代码段:

typedef double db;
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef pair<int,int> pa;
typedef unsigned int uint;
typedef unsigned long long ull;

就是定义各种类型的缩写,有些类型太长了,写起来都不太愿意,而且DEV又没有什么代码自动补全。

比较常用的就是long long,比如之前定义这个类型要long long a=1;现在只要ll a=1;就行了,贼方便。接下来看代码段:

const int maxn=1005,inf=1<<29,mod=1000000007;
const double pi=acos(-1.0);

定义了一些常用的常量,比如用来表示数组的最大值的maxn,无穷大inf,还有表示模的mod,以及π的精确表示pi。

接下来的代码段:

bool sf(int &x){return scanf("%d",&x)==1;}
bool sf(ll &x){return scanf("%I64d",&x)==1;}
bool sf(double &x){return scanf("%lf",&x)==1;}
bool sf(char &x){return scanf("%c",&x)==1;}
bool sf(char *x){return scanf("%s",x)==1;}
bool sf(string &x){return cin>>x;}

利用函数重载把常见的一些数据类型进行了读取。函数传的是引用,返回值代表有没有数据读入,这在多组输入中有用。

然后接下来的代码段:

template<class T>inline void sf2(T&num){
    num=0;T f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
    num*=f;
}

这是个读入函数,优点是比前面的读入快,特别是输入数据量比较大的时候就能体现出它的价值了,可以叫它“读入外挂”。利用模板template来接受任何类型的参数,当然函数内的实现决定了,这只对整数有用。

接下来的代码段:

void pf(int x,int op){op==0?printf("%d",x):printf("%d%c",x,op==1?' ':'\n');}
void pf(ll x,int op){op==0?printf("%I64d",x):printf("%I64d%c",x,op==1?' ':'\n');}
void pf(char x,int op){op==0?printf("%c",x):printf("%c%c",x,op==1?' ':'\n');}
void pf(char *x,int op){op==0?printf("%s",x):printf("%s%c",x,op==1?' ':'\n');}
void pf(string x,int op){op==0?cout<<x:cout<<x<<(op==1?' ':'\n');}

利用函数重载实现各种各样的常用输出。

op是控制输出变量后面跟的是什么,0代表什么都不跟,1代表跟空格,2代表跟换行。

接下来的代码段:

inline int gcd(int x,int y){if(!x)return y;return gcd(y%x,x);}
inline int power(int x,int k,int p){int res=1;for(;k;k>>=1,x=(ll)x*x%p)if(k&1)res=(ll)res*x%p;return res;}

gcd函数用来求两个数的最大公约数,power用来求快速幂x^k%p。这两个函数在数论中经常用到。

接下来的代码段:

int n,m,k;
int dp[maxn][maxn],a[maxn][maxn];
int dir[][2]={{0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};

n,m,k是常用的变量,dp,a是常用数组,dir是常用方向数组。在搜索里面用得比较多,用来向相邻的八个方向扩散。

以上,完毕。

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值