本篇不着重于具体问题的算法流程,主要分享个人认为的算法之外的一些注意点以及编码技巧。确保在已知解题算法的前提下能用“一套连招快速带走”题目,而不至于惨死在算法之外的方方面面。这样也可以让我们把更多精力放在算法设计方面,避免浪费大量时间。
scanf()
和printf()
,且尽量不要将std::cin
和scanf()
以及std::cout
和printf()
混着用(有时会出现问题,比如下面的情况,用于加速std::cin和std::cout,此时绝对不能把C和C++的输出混着用,具体实例见[1])。 std::ios::sync_with_stdio(false); // 取消cout和printf的兼容,此后不能将输出流混用
std::cin.tie(0); // 解除std::cin和std::cout的绑定
long long类型的输入输出:scanf("%I64d", &n);
。注意是字母I(i),不是l(L),且一定是大写。注:在洛谷做题时,%I64d
要改为%lld
。
输出带前导零的整数,比如时间格式HH::MM::SS
,打印语句应为printf("%02d:%02d:%02d\n", h, m, s);
,其他情况依此类推。
#define MAXN (1e5 + 5)
会抛出异常size of array 'A' has non-integral type 'double'
,因为数组下标必须为整数类型。#define MAXN 100005
int A[MAXN];
left
,right
,count
,map
等。注意原始输入数组A
的下标,线段树模板的根节点下标通常为1,则数组A
的起始点下标尽量也从1开始;若A
从下标0开始,则需要进行统一下标的操作。比如下面这段代码,其实现了点修改的线段树,由于输入数组从0开始,故需要在建树和调用时进行下标转换,原题见 leetcode307.区域和检索。
class NumArray {
private:
int n;
typedef struct{
int l, r;
int sumv;
}tree;
#define MAXN 30001
tree T[MAXN*4];
// 建树
void build(int o, vector<int>& A){
int L = T[o].l, R = T[o].r;
int lc = o*2, rc = o*2+1;
if(L == R){
T[o].sumv = A[L-1]; // 1:下标要减1, A[0...n-1]
return;
}
int M = L + (R - L) / 2;
T[lc].l = L, T[lc].r = M;
T[rc].l = M+1, T[rc].r = R;
build(lc, A);
build(rc, A);
T[o].sumv = T[lc].sumv + T[rc].sumv;
}
void pushup(int o){
T[o].sumv = T[o*2].sumv + T[o*2+1].sumv;
}
void update(int o, int x, int val){
int L = T[o].l, R = T[o].r;
if(L == R){
T[o].sumv = val;
return;
}
else{
int M = L + (R - L) / 2;
if(x <= M){
update(o*2, x, val);
}
else{
update(o*2+1, x, val);
}
pushup(o);
}
}
int query(int o, int ql, int qr){
int L = T[o].l, R = T[o].r;
if(ql <= L && R <= qr){
return T[o].sumv;
}
int M = L + (R - L) / 2;
int sumv = 0;
if(ql <= M){
sumv += query(o*2, ql, qr);
}
if(qr > M){
sumv += query(o*2+1, ql, qr);
}
return sumv;
}
public:
NumArray(vector<int>& nums) {
n = nums.size();
T[1].l = 1, T[1].r = n;
build(1, nums);
}
void update(int index, int val) {
update(1, index+1, val); // 2:下标index要加1
}
int sumRange(int left, int right) {
return query(1, left+1, right+1); // 3:0 <= left, right < n,要加1
}
};
freopen
函数进行输入输出流的重定向,把数据放在文件里,笔者这里给个简易调试模板,默认情况下在执行代码的当前文件夹下新建一个名称为in1.txt
的文件,用于存放用例输入,注意数据文件第一行为用例的数目;提交代码时只需要把#define DEBUGMODE
注释掉即可。#include
#include // freopen()在此标准库中
using namespace std;
#define DEBUGMODE // 提交代码时注释掉即可
int main(){
int tCase = 1; // 测试用例数目
#ifdef DEBUGMODE
freopen("in1.txt", "r", stdin);
scanf("%d", &tCase);
//freopen("out1.txt", "w", stdout); // 如果想把结果保存到文件,取消该句注释
#endif
while (tCase--){
// 在这里放置算法的代码
// ...
}
#ifdef DEBUGMODE
cin.get(); // 用stdout时,避免界面直接关闭,从而看不到输出结果
cin.get();
#endif
return 0;
}
如果本文有描述不妥的地方,或是有更好的方案,欢迎交流与指正!
[1] LT-Y. sync_with_stdio(false)的副作用[EB/OL]. https://www.cnblogs.com/Little-Turtle–QJY/p/13832888.html, 2020-10-17.