一些在代码里的好用的技巧和偷懒
0.注意
- 所有技巧都可以在
OI中使用。 - 至少在
C++ 14支持。 - 在
MinGW64中支持,大部分在clang里支持。
1
作者不太会用 define,如果你也一样那么 using 会很适合你。
调整到 C++14 及以后的版本。我一般喜欢写:
using LL=long long;//直接写在头文件下面
//using identifier attr (optional) = type-id ;应该很容易看懂,就是把 LL 代替 long long,但是就是只能用来代替数据类型,自由度要比 define 差一些。
2
输入输出,好的作者又不会 scanf,一般来讲直接关闭同步流的 cin/cout 完全够了。
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cout<<fixed<<setprecision<<(n)<<x;//这是输出x保留n位小数但是有些时候还是需要快读,通常是读入量超过 $10^7$ 的时候,其实一般不会有这么多输出,这是我的快读模板;
LL res=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();};
while(c>='0'&&c<='9'){res=(res<<3)+(res<<1)+c-'0';};
return res*f;3
平时的模拟赛一般还是用数组稳当一些,毕竟空间大小确定,而且常数小,在函数调用时方便传参。但是有些时候,特别是做 CF 的题的时候,数据量不大,也不卡常,用 vector 是一个不错的选择,如果你之前不怎么用,可以试试下面几个常用操作:
vector<LL> a;//定义一个空的vector,可以用push_back来添加元素。
vector<LL> a(n);//大小为n,注意和数组一样这里是指 0 -- n-1,所以记得要比实际的大一下。
vector<LL> a(n,x);//所以元素初值为x
a.assign(n,x);//重新初始化
sort/lower_bound/unique/...(a.begin(),a.end());//在函数中调用时4
auto 是个好东西,适合多用,特别是遇到指针或者很多结构体的时候很好用,还有就是循环的时候。
5
离散化的写法很多,有些用存下标的方法,但是二分查找更方便写,而且其实你只需要两行就秒了:
sort(a.begin(),a.end());//这里a是一个vector。
a.erase(unique(a.begin(),a.end()),a.end());
LL k=lower_bound(a.begin(),a.end(),x)-a.begin()+1;//x离散化后的数为k6
有时候需要在不同的函数里面调用同名但是不同的函数,或者为了方便,或者为了在函数中使用没有全局定义的变量又不想传参,就可以试试 std::function,其实跑的比一般递归要快。
先来看看不递归的怎么写:
auto check=[](string s){
if(s=="IGpig") return 1;
else return 0;
};
auto p=check("happypigIG");//p=0
sort(a+1,a+n+1,[](){return };);//也可以挂在sort,lower_bound等后面用
然后如果你想要递归,就要每次都调用自己,但是自己都还没有定义怎么调用,那就吧自己当成参数:
auto dfs=[&](auto self,LL x)->void{// [&] 只会捕获用到的变量,所以不会捕获 auto dfs
if (x==y) return;
else self(self, x+1);
};
dfs(dfs,1);这样就不用怕 $y$ 不是全局变量了,也能让代码看起来简单一些。
7
很多时候,其实你会发现 memset 这个东西一点都不好用,难写,能赋的值很少,只能赋值整个数组,一般不是常数。我们如果用 fill 就可以了,其实她的底层原理还是 memset:
LL a[10];
fill(a+1,a+10,2);//std::fill(LL *__first, LL *__last, const int &__value)8
重载运算符,通常用在结构体的时候,一个很有用的地方就是在线段树查询的时候如果返回值是一个结构体,大家是不是在合并两边的 $res$ 的时候还要再写一遍 pushup 里的内容。但是在定义结构体的时候就可以重载,比如我们要同时维护和和最大值:
struct node{
LL sum,mx;
friend node operator+(node x,node y){//这里的node是指返回值的类型,如果你想重载<,=或>,就用bool
node res;
res.sum=x.sum+y.sum;
res.mx=max(x.mx,y.mx);
return res;
}
};9
平时写题的时候经常需要复制各种东西然后每次测样例还要去复制一次,很麻烦,所以我选择用文件读写,但是提交上去还要注释,不过大部分 OJ 都开了 ONLINE_JUDGE 编译选项,所以使用这个代码很不错,每次先把样例放进去:
int main(){
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
#else
freopen("tinput.txt", "r", stdin);
#endif10
在写多组数据的题不想单独开函数就想写在主函数里而且不想写while的话:
int main() {
static LL t = -1;
if (t == -1) {
cin >> T;
}
if (t-- == 0) return 0;
main();
}11
最后是小猪的线段树模板:
struct seg_tree{
#define lson l,mid,x<<1
#define rson mid+1,r,x<<1|1
#define mid ((l+r)>>1)
LL tr[400005];
void pushup(LL x){
tr[x]=max(tr[x<<1],tr[x<<1|1]);
}
void update(LL L,LL R,LL d,LL l,LL r,LL x){
if(L<=l&&r<=R){
tr[x]=d;
return ;
}
if(L<=mid) update(L,R,d,lson);
if(mid<R) update(L,R,d,rson);
pushup(x);
}
LL query(LL L,LL R,LL l,LL r,LL x){
if(L<=l&&r<=R){
return tr[x];
}
LL res=0;
if(L<=mid) res=max(res,query(L,R,lson));
if(mid<R) res=max(res,query(L,R,rson));
return res;
}
}tree;