上回反响不行啊……
这会Miemeng要给大家三个考试技巧!
1.‘#’系列(预处理器)
#if
#ifdef
#ifndef
#elif
#endif
#undef
#define
上面这些非常有用!
我们主要说一下 #ifdef 这样的(有用!)
考试时往往要开 freopen 于是有人忘了,有人不习惯文件输入输出
所以用下面的代码片:
#include <bits/stdc++.h>
using namespace std;
int main(){
#ifndef LC
/*LC 也可以写自己喜欢的变量名*/
freopen("*.in" ,"r",stdin);
freopen("*.out","w",stdout);
#endif
/*照常打代码*/
}
稍稍解释一下:
#if 就类比于 if ,只是针对编译器起作用,意思就是说后面是 true 就编译下面的语句(不要以为你可以在后面加一个变量)
于是 #endif 是结束这个过程(一个 if 管全局要命啊)
那么 #ifdef 就是另一个版本,意思是说后面的宏(可以理解为一个常量)被定义了,就编译下面的语句
#ifndef 就是$if\ not\ define$,可以理解是上面的取非。
#elif 就很好理解了吧,就是类似$else \, if$的东西
如果要和 #ifdef 一起用还要写个 #elif defined A (如果上面的未定义却定义了A,就编译下面的语句,否则跳过跳到 #endif )
说这么大一坨其实也没啥用
下面说一个必须要知道的东西:
当你使用了上面的代码片后,$g++$编译,你就会发现它还是文件输入输出(不要打我啊,还没有说完)(别打脸……啊)
因为你并没有定义$LC$所以还是没法跳过 freopen ,
于是用下面的$g++$编译
g++ file.cpp -o file -D LC
后面的 -D LC 非常好理解啊,就是在编译时定义一下$LC$
发现还有一个#undef
与#define 相对
将后面的宏解除定义
#include <iostream>
#define N 123
using namespace std;
int main(){
cout<<N<<endl;//输出123
#undef N
cout<<N<<endl;//这里会告诉你N没定义
}
剩下的就是没啥用的了:
#error
#warning
#pragma
#pragma大家应该都明白是什么……
这里说一个:message("sting")
用法:
#pragma message( "输出一条Note!" )
作用?也许并没有
#error是好东西(虽然没有什么用)
#error 输出一条error,不写引号也可以!
#warning就不好用了,它只能控制警告的输出QwQ(所以根本没有用)
至于到底怎么用,去$C++$手册
2.文件流 & 字符串流
别以为名字很高大上就很厉害,其实和第一课学的$cin$ $cout$是兄弟
文件流:
调库:
#include <fstream>
定义:
fstream a,b,c,d;
使用:
首先打开文件:
a.open("文件名",/*参数*/ios_base::in);
后面的参数有下面几种:
ios_base::in //输入(类比与cin)
ios_base::out //输出 (类比与cout)
ios_base::app//在文件的末尾cout (不新建文件)
所以给个例子:
#include <bits/stdc++.h>
#define N 101010
using namespace std;
void ran(){
int l,c,qn;
fstream rin,rout;
rin.open("std",ios_base::in);
rout.open("vegetable.in",ios_base::out);
rin>>l>>c>>qn;
rout<<l<<" "<<c<<" "<<qn<<endl;
for(int i=1;i<=l;i++){
for(int j=1;j<=c;j++){
rout<<rand()%100000<<" ";
}rout<<endl;
}
for(int i=1;i<=qn;i++){
int a=rand()%l+1,b=rand()%c+1,
c=rand()%l+1,d=rand()%c+1;
rout<<min(a,c)<<" "<<min(b,d)<<" "<<max(a,c)<<" "<<max(b,d)<<endl;
}rout<<endl;
}
int main(){
int T=N;
srand(time(0));
//ran();return 0;
while(T--){
if(T%10000==0)srand(time(0));
ran();
system("time ./ac");
system("./bl");
if(system("diff ac.out bl.out")){
puts("WA");
return 0;
}
cout<<T<<"/"<<N<<"AC"<<endl;
}
}
所以研究一番代码,发现这是把ran直接揉到对拍里写的
有什么好处?
- 可以把一个随机数时间种子充分利用,比如上面的代码中每个种子中,随机数用了10000次
- 可以实时控制对拍进程,发现可以再开一个流输入数据参数,于是可以在一次对拍中随时更改数据范围……
字符串流:
调库:
#include <sstream>
定义:
stringstream q;
使用:
就是把一个数输到字符串里,或是从字符串里读出一个数
(没啥用,而且特特特特特特特特特特别慢)
具体例子可以看这个一件建文件的代码(别乱改,容易爆,或者先把死循环打掉)
#include <bits/stdc++.h>
using namespace std;
string p,x;
int main(){
fstream init;
init.open("Number.pre",ios_base::in);
if(init.is_open()){
init>>p>>x;
}
else {
init.close();
init.open("Number.pre",ios_base::out);
init.close();
init.open("Error",ios_base::out);
init<<"Need A File Named Number.pre\nA *.pre file is for File name"<<endl;
init.close();
return 0;
}
for(int i=0;;i++){
stringstream q;
string k;
q<<i;
q>>k;
k=p+k+x;
fstream a;
a.open(k.c_str(),ios_base::in);
if(a.is_open()){
a.close();
}
else{
fstream b;
b.open(k.c_str(),ios_base::out);
b.close();
return 0;
}
}
}
3.STL的一点点骗分技巧
mt19937
基于梅森缠绕器算法,可以产生循环节长达$2^{19937}$的随机数(至于梅森缠绕器,我也不知道那是啥)
用法?和 rand() 一样
调库:
#include <random>
使用:
#include <bits/stdc++.h>
using namespace std;
mt19937 ran(time(0));
int main(){
cout<<ran()<<endl;
}
好简单啊~~记得开C++11
数据结构(杂)
vector 可以 reserve 来分配内存防止它倍增到你MLE
#include <bits/stdc++.h>
using namespace std;
vector<int>k;
int main(){
k.reserve(100);
}
unordered_map 是基于 hash 的$O(1)$查询map
#include <unordered_map>
using namespace std;
unordered_map<int,int>k;
int main(){
k.rehash(100);
}
P.S. 别忘了开C++11
完结了,累死了……
可能不会再更了(倾出了毕生绝学)