杂项
自动判断输入结束
按位取反,简单地说就是二进制1变0,0变1
由于scanf是有返回值的,且返回值为int型
特别的此处用法导致只有scanf返回-1,循环才会结束,也就是要返回EOF
while (~scanf("%d%d",&n,&m))
等效于
while (scanf("%d%d",&n,&m)!=EOF)
其实这样也行
while (cin >> x)
只有-1 补码的取反后全为0,终止循环。
未定义的行为
Undefined Behavior,简称UB
经常是在同一语句中对某个变量进行多个操作然后产生了歧义,此时不同编译器可以自己选择解释方式
如 P3141 [USACO16FEB]Fenced In P 中对数据的处理就容易出现歧义
- 本地AC但洛谷WA的代码
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int s[N], t[N];
int n, m, a[N], b[N], r, c;
long long ans;
int main() {
scanf("%d%d%d%d", &r, &c, &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &s[i]);
for(int j = 1; j <= m; ++j) scanf("%d", &t[j]);
sort(s + 1, s + n + 1);
sort(t + 1, t + m + 1);
for(int i = 1; i <= n; ++i) b[i] = s[i] - s[i - 1];
b[++n] = r - s[n - 1];
for(int i = 1; i <= m; ++i) a[i] = t[i] - t[i - 1];
a[++m] = c - t[m - 1];
swap(n, m);
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1);
int it1 = 2, it2 = 2, h1 = 1, h2 = 1;
ans += (long long)a[1] * (m - 1);
ans += (long long)b[1] * (n - 1);
while(it1 <= n && it2 <= m) {
if(a[it1] > b[it2]) {
ans += (long long)b[it2] * (n - h1);
++it2;
++h2;
}
else {
ans += (long long)a[it1] * (m - h2);
++it1;
++h1;
}
}
printf("%lld", ans);
return 0;
}
/*
输入:
15 15 5 2
2
5
10
6
4
11
3
本地输出:
44
洛谷IDE:
52
那究竟是什么导致的呢?
其实问题出在这里:
for(int i = 1; i <= n; ++i) b[i] = s[i] - s[i - 1];
b[++n] = r - s[n - 1];
for(int i = 1; i <= m; ++i) a[i] = t[i] - t[i - 1];
a[++m] = c - t[m - 1];
第二行和第四行的++m和m-1纠缠在了一起,本地的gcc编译器和洛谷ide的clang各执一词,才发生了交了十多次都是全wa的悲剧。
而解决的方法也很简单,只要像下面这样拆开来就好了
for(int i = 1; i <= n; ++i) b[i] = s[i] - s[i - 1];
b[n + 1] = r - s[n];
++n;
for(int i = 1; i <= m; ++i) a[i] = t[i] - t[i - 1];
a[m + 1] = c - t[m];
++m;
所以之后遇到++某个变量这种操作,最好进行一下隔离,特别是不要和其它对这个变量的操作放在同一条语句中……
Linux调试台小芝士
最常见的c++编译语句:
g++ test.cpp -o test
//编译器名称 源文件名称 编译指令 可执行文件名
//可执行文件名要放在编译指令的后面
分段编译
一个C/C++源代码要变成一个可执行文件,需要经过预处理(Pre-processing)-编译(Compiling)-汇编(Assembling)-链接(Link)
基本流程为:
test.cpp --预处理--test.i --编译-- test.s --汇编-- test.o --链接-- test.exe
- 预处理
-E 选项使用g++/gcc将源代码预处理后不执行其他动作。
下面的命令将test.cpp预处理,并在标准输出中显示
g++ -E test.cpp
后面加上 -o 选项表示将源代码预处理后输出在指定文件中,比如test.i:
g++ -E test.cpp -o test.i
- 编译
-S 选项使用g++/gcc将预处理后的文件编译,翻译成汇编代码。只编译不汇编
下面的命令将会编译test.i文件,并自动在当前文件夹生成test.s文件
g++ -S test.i
若要指定其他输出名,则需 -o 指定,比如生成名为xxx.s的汇编代码文件
g++ -S test.i -o xxx.s
- 汇编
-c 选项将编译生成的test.s文件生成二进制目标代码
下面的命令将在当前文件夹自动生成test.o的二进制目标代码文件
g++ -c test.s
如果要指定输出文件名,则需 -o 指定,比如生成xxx.o的二进制目标代码文件
g++ -c test.s -o xxx.o
- 链接
链接阶段是将相关的目标文件链接起来,形成一个整体,生成可执行文件
无选项链接
下面的命令会把二进制目标文件test.o所需的相关文件链接成一个整体,并在当前文件夹自动生成一个名为a.out的可执行文件
g++ test.o
如果要执行这个可执行文件,需要输入命令
./a.out
当然也可以指定生成的可执行文件的文件名
g++ test.o -o test.exe
- 单个源文件直接编译
很明显,这当然可以,毕竟前面写过了
非指定文件名(生成a.out):
g++ test.cpp
指定文件名(要加-o选项):
g++ test.cpp -o test
- 多个源文件直接生成可执行文件
也可以将多个源代码编译链接成一个可执行文件
下面的命令将test.cpp直接在当前文件夹生成a.out可执行文件,若要指定文件名,可使用 -o 选项
//应该是给一些项目用的,反正咱应该暂时用不到
//直接生成
g++ test1.cpp test2.cpp
//规定文件名
g++ test1.cpp test2.cpp -o test.exe
编译选项
一般有如下几个(放的位置自己琢磨):
-o
//指定可执行文件名,可执行文件名要接在后面
-std=c++14
//以c++14的标准编译,拥有c++14的特性
-O2
//O2优化
-lm
//某数学库,似乎没啥用
-Wall
//显示所有警告
-W
//不显示警告
中断运行时的程序
当遇到死循环或者要终端的时候
用ctrl + z 或者是 ctrl + c 中断运行
__int128
int128除了比较长之外没啥用处……
而且仅有四则运算功能……
而且还要手写输入输出……
输入输出板子:
#define int __int128
inline void read(int &n){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
n=x*f;
}
inline void print(int n){
if(n<0){
putchar('-');
n*=-1;
}
if(n>9) print(n/10);
putchar(n % 10 + '0');
}
#undef int
例题(见第二题)
gdb调试器
- 较详细的gdb入门教程